Interpreter entries and instrumentation as a listener.
Make the instrumentation responsible for whether we want method entry/exit
stubs, and allow it to use interpreter entry stubs when instruction by
instruction instrumentation is required. Improve deoptimization so more JDWP
test cases are passing.
Refactor exception debug posting, in particular improve reporting in the
interpreter. Improve class linker exception throwing so that broken dex files
are more likely to be reported. Fixes the performance issue Bug: 8410519.
Fix some error reporting lock level errors for the large object space. Make
fast object verification faster.
Add some debug mode robustness to finding dex PCs in GC maps.
Add printf attributes to JniAbortF and fix errors.
Expand run-test 044 to test return behaviors and fix issues with not throwing
appropriate exceptions for proxies.
Ensure causes are reported with a class linker NoClassDefFoundError and JNI
NoSuchFieldError.
Remove unused debugMe and updateDebuggerFromCode.
There's a minor sizing tweak to the arg array builder, and an extra reference
array check in the interpreter.
Some clean-up of trace code.
Fix reg type cache destructor if it is called after the reg type cache is
shutdown (as is the case in oatdump).
Change-Id: I6519c7b35df77f978d011999354c864f4918e8ce
diff --git a/src/compiler/dex/frontend.h b/src/compiler/dex/frontend.h
index 2e62dc8..49e0852 100644
--- a/src/compiler/dex/frontend.h
+++ b/src/compiler/dex/frontend.h
@@ -55,7 +55,6 @@
// Force code generation paths for testing.
enum debugControlVector {
- kDebugDisplayMissingTargets,
kDebugVerbose,
kDebugDumpCFG,
kDebugSlowFieldPath,
diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc
index c13e797..4fadc9d 100644
--- a/src/compiler/dex/quick/gen_common.cc
+++ b/src/compiler/dex/quick/gen_common.cc
@@ -507,17 +507,6 @@
}
}
-
-// Debugging routine - if null target, branch to DebugMe
-void Mir2Lir::GenShowTarget()
-{
- DCHECK_NE(cu_->instruction_set, kX86) << "unimplemented GenShowTarget";
- LIR* branch_over = OpCmpImmBranch(kCondNe, TargetReg(kInvokeTgt), 0, NULL);
- LoadWordDisp(TargetReg(kSelf), ENTRYPOINT_OFFSET(pDebugMe), TargetReg(kInvokeTgt));
- LIR* target = NewLIR0(kPseudoTargetLabel);
- branch_over->target = target;
-}
-
void Mir2Lir::HandleSuspendLaunchPads()
{
LIR** suspend_label = reinterpret_cast<LIR**>(suspend_launchpads_.elem_list);
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index 3e946f8..c0bae29 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -1375,9 +1375,6 @@
vtable_idx, direct_code, direct_method,
original_type);
}
- if (cu_->enable_debug & (1 << kDebugDisplayMissingTargets)) {
- GenShowTarget();
- }
LIR* call_inst;
if (cu_->instruction_set != kX86) {
call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
diff --git a/src/compiler/dex/quick/mir_to_lir.h b/src/compiler/dex/quick/mir_to_lir.h
index 69ebc7e..aec0cc1 100644
--- a/src/compiler/dex/quick/mir_to_lir.h
+++ b/src/compiler/dex/quick/mir_to_lir.h
@@ -396,7 +396,6 @@
bool is_long_or_double, bool is_object);
void GenSget(uint32_t field_idx, RegLocation rl_dest,
bool is_long_or_double, bool is_object);
- void GenShowTarget();
void GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double, bool is_object);
void GenIPut(uint32_t field_idx, int opt_flags, OpSize size,
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 700936c..4e8ebbd 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -1202,9 +1202,8 @@
manager->GetClassLinker()->FindClass(descriptor,
soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()));
if (klass == NULL) {
- Thread* self = Thread::Current();
- CHECK(self->IsExceptionPending());
- self->ClearException();
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
/*
* At compile time, we can still structurally verify the class even if FindClass fails.
@@ -1230,13 +1229,13 @@
if (klass->IsErroneous()) {
// ClassLinker::VerifyClass throws, which isn't useful in the compiler.
- CHECK(Thread::Current()->IsExceptionPending());
- Thread::Current()->ClearException();
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
}
CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
<< PrettyDescriptor(klass) << ": state=" << klass->GetStatus();
- CHECK(!Thread::Current()->IsExceptionPending()) << PrettyTypeOf(Thread::Current()->GetException());
+ soa.Self()->AssertNoPendingException();
}
void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
@@ -1435,7 +1434,6 @@
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def);
mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader);
- Thread* self = Thread::Current();
bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
bool can_init_static_fields = compiling_boot &&
manager->GetCompiler()->IsImageClass(descriptor);
@@ -1447,9 +1445,9 @@
// its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
// lock ordering and consequent potential deadlock.
static Mutex lock1("Initializer lock", kMonitorLock);
- MutexLock mu(self, lock1);
+ MutexLock mu(soa.Self(), lock1);
// The lock required to initialize the class.
- ObjectLock lock2(self, klass);
+ ObjectLock lock2(soa.Self(), klass);
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
@@ -1473,7 +1471,7 @@
} else {
manager->GetClassLinker()->EnsureInitialized(klass, true, can_init_static_fields);
}
- CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
+ soa.Self()->AssertNoPendingException();
}
}
}
@@ -1494,7 +1492,7 @@
}
}
// Clear any class not found or verification exceptions.
- self->ClearException();
+ soa.Self()->ClearException();
}
void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
@@ -1651,7 +1649,7 @@
if (self->IsExceptionPending()) {
ScopedObjectAccess soa(self);
LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
- << self->GetException()->Dump();
+ << self->GetException(NULL)->Dump();
}
}
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index d9b879a..d6c8181 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -135,15 +135,16 @@
obj->MonitorExit(thread);
}
-void art_portable_test_suspend_from_code(Thread* thread)
+void art_portable_test_suspend_from_code(Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CheckSuspend(thread);
- if (thread->ReadFlag(kEnterInterpreter)) {
+ CheckSuspend(self);
+ if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) {
// Save out the shadow frame to the heap
- ShadowFrameCopyVisitor visitor(thread);
+ ShadowFrameCopyVisitor visitor(self);
visitor.WalkStack(true);
- thread->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy(), JValue());
- thread->SetException(reinterpret_cast<mirror::Throwable*>(-1));
+ self->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy());
+ self->SetDeoptimizationReturnValue(JValue());
+ self->SetException(ThrowLocation(), reinterpret_cast<mirror::Throwable*>(-1));
}
}
@@ -175,51 +176,59 @@
}
void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Thread::Current()->ThrowNewException("Ljava/lang/ArithmeticException;",
- "divide by zero");
+ ThrowArithmeticExceptionDivideByZero(Thread::Current());
}
void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
- "length=%d; index=%d", length, index);
+ ThrowArrayIndexOutOfBoundsException(index, length);
}
void art_portable_throw_no_such_method_from_code(int32_t method_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // We need the calling method as context for the method_idx.
- mirror::AbstractMethod* method = Thread::Current()->GetCurrentMethod();
- ThrowNoSuchMethodError(method_idx, method);
+ ThrowNoSuchMethodError(method_idx);
}
void art_portable_throw_null_pointer_exception_from_code(uint32_t dex_pc)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::AbstractMethod* throw_method =
- Thread::Current()->GetManagedStack()->GetTopShadowFrame()->GetMethod();
- ThrowNullPointerExceptionFromDexPC(throw_method, dex_pc);
+ // TODO: remove dex_pc argument from caller.
+ UNUSED(dex_pc);
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ ThrowNullPointerExceptionFromDexPC(throw_location);
}
void art_portable_throw_stack_overflow_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ThrowStackOverflowError(Thread::Current());
}
-void art_portable_throw_exception_from_code(mirror::Object* exception) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Thread::Current()->DeliverException(static_cast<mirror::Throwable*>(exception));
+void art_portable_throw_exception_from_code(mirror::Throwable* exception)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ if (exception == NULL) {
+ ThrowNullPointerException(NULL, "throw with null exception");
+ } else {
+ self->SetException(throw_location, exception);
+ }
}
void* art_portable_get_and_clear_exception(Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(self->IsExceptionPending());
- mirror::Throwable* exception = self->GetException();
+ // TODO: make this inline.
+ mirror::Throwable* exception = self->GetException(NULL);
self->ClearException();
return exception;
}
int32_t art_portable_find_catch_block_from_code(mirror::AbstractMethod* current_method, uint32_t ti_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Throwable* exception = Thread::Current()->GetException();
- // Check for magic deoptimization exception.
- if (reinterpret_cast<int32_t>(exception) == -1) {
+ Thread* self = Thread::Current(); // TODO: make an argument.
+ ThrowLocation throw_location;
+ mirror::Throwable* exception = self->GetException(&throw_location);
+ // Check for special deoptimization exception.
+ if (UNLIKELY(reinterpret_cast<int32_t>(exception) == -1)) {
return -1;
}
mirror::Class* exception_type = exception->GetClass();
@@ -229,26 +238,40 @@
const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
int iter_index = 0;
+ int result = -1;
+ uint32_t catch_dex_pc = -1;
// Iterate over the catch handlers associated with dex_pc
for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) {
uint16_t iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
if (iter_type_idx == DexFile::kDexNoIndex16) {
- return iter_index;
+ catch_dex_pc = it.GetHandlerAddress();
+ result = iter_index;
+ break;
}
// Does this catch exception type apply?
mirror::Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
- if (iter_exception_type == NULL) {
- // The verifier should take care of resolving all exception classes early
+ if (UNLIKELY(iter_exception_type == NULL)) {
+ // TODO: check, the verifier (class linker?) should take care of resolving all exception
+ // classes early.
LOG(WARNING) << "Unresolved exception class when finding catch block: "
<< mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
} else if (iter_exception_type->IsAssignableFrom(exception_type)) {
- return iter_index;
+ catch_dex_pc = it.GetHandlerAddress();
+ result = iter_index;
+ break;
}
++iter_index;
}
- // Handler not found
- return -1;
+ if (result != -1) {
+ // Handler found.
+ Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(self,
+ throw_location,
+ current_method,
+ catch_dex_pc,
+ exception);
+ }
+ return result;
}
@@ -640,14 +663,12 @@
DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
DCHECK(src_type->IsClass()) << PrettyClass(src_type);
if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
- "%s cannot be cast to %s",
- PrettyDescriptor(src_type).c_str(),
- PrettyDescriptor(dest_type).c_str());
+ ThrowClassCastException(dest_type, src_type);
}
}
-void art_portable_check_put_array_element_from_code(const mirror::Object* element, const mirror::Object* array)
+void art_portable_check_put_array_element_from_code(const mirror::Object* element,
+ const mirror::Object* array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (element == NULL) {
return;
@@ -658,10 +679,7 @@
mirror::Class* component_type = array_class->GetComponentType();
mirror::Class* element_class = element->GetClass();
if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
- "%s cannot be stored in an array of type %s",
- PrettyDescriptor(element_class).c_str(),
- PrettyDescriptor(array_class).c_str());
+ ThrowArrayStoreException(element_class, array_class);
}
return;
}