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/stack.cc b/src/stack.cc
index 66051f2..8690a36 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -24,9 +24,28 @@
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "thread_list.h"
+#include "throw_location.h"
namespace art {
+mirror::Object* ShadowFrame::GetThisObject() const {
+ mirror::AbstractMethod* m = GetMethod();
+ if (m->IsStatic()) {
+ return NULL;
+ } else if (m->IsNative()) {
+ return GetVRegReference(0);
+ } else {
+ const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+ CHECK(code_item != NULL) << PrettyMethod(m);
+ uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+ return GetVRegReference(reg);
+ }
+}
+
+ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
+ return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
+}
+
size_t ManagedStack::NumJniShadowFrameReferences() const {
size_t count = 0;
for (const ManagedStack* current_fragment = this; current_fragment != NULL;
@@ -59,7 +78,7 @@
: thread_(thread), cur_shadow_frame_(NULL),
cur_quick_frame_(NULL), cur_quick_frame_pc_(0), num_frames_(0), cur_depth_(0),
context_(context) {
- DCHECK(thread == Thread::Current() || thread->IsSuspended());
+ DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
}
uint32_t StackVisitor::GetDexPc() const {
@@ -72,6 +91,33 @@
}
}
+mirror::Object* StackVisitor::GetThisObject() const {
+ mirror::AbstractMethod* m = GetMethod();
+ if (m->IsStatic()) {
+ return NULL;
+ } else if (m->IsNative()) {
+ if (cur_quick_frame_ != NULL) {
+ StackIndirectReferenceTable* sirt =
+ reinterpret_cast<StackIndirectReferenceTable*>(
+ reinterpret_cast<char*>(cur_quick_frame_) +
+ m->GetSirtOffsetInBytes());
+ return sirt->GetReference(0);
+ } else {
+ return cur_shadow_frame_->GetVRegReference(0);
+ }
+ } else {
+ const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+ if (code_item == NULL) {
+ UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method"
+ << PrettyMethod(m);
+ return NULL;
+ } else {
+ uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+ return reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kReferenceVReg));
+ }
+ }
+}
+
size_t StackVisitor::GetNativePcOffset() const {
DCHECK(!IsShadowFrame());
return GetMethod()->NativePcOffset(cur_quick_frame_pc_);
@@ -198,7 +244,7 @@
return result;
}
-InstrumentationStackFrame StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
+instrumentation::InstrumentationStackFrame StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
return thread_->GetInstrumentationStack()->at(depth);
}
@@ -221,9 +267,8 @@
void StackVisitor::WalkStack(bool include_transitions) {
DCHECK(thread_ == Thread::Current() || thread_->IsSuspended());
- const std::deque<InstrumentationStackFrame>* instrumentation_stack =
- thread_->GetInstrumentationStack();
- bool method_tracing_active = instrumentation_stack != NULL;
+ CHECK_EQ(cur_depth_, 0U);
+ bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
uint32_t instrumentation_stack_depth = 0;
for (const ManagedStack* current_fragment = thread_->GetManagedStack(); current_fragment != NULL;
current_fragment = current_fragment->GetLink()) {
@@ -235,6 +280,7 @@
DCHECK(current_fragment->GetTopShadowFrame() == NULL);
mirror::AbstractMethod* method = *cur_quick_frame_;
while (method != NULL) {
+ DCHECK(cur_quick_frame_pc_ != GetInstrumentationExitPc());
SanityCheckFrame();
bool should_continue = VisitFrame();
if (UNLIKELY(!should_continue)) {
@@ -248,16 +294,24 @@
size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
- if (UNLIKELY(method_tracing_active)) {
+ if (UNLIKELY(exit_stubs_installed)) {
// While profiling, the return pc is restored from the side stack, except when walking
// the stack for an exception where the side stack will be unwound in VisitFrame.
- // TODO: stop using include_transitions as a proxy for is this the catch block visitor.
- if (GetInstrumentationExitPc() == return_pc && !include_transitions) {
- // TODO: unify trace and managed stack.
- InstrumentationStackFrame instrumentation_frame = GetInstrumentationStackFrame(instrumentation_stack_depth);
+ if (GetInstrumentationExitPc() == return_pc) {
+ instrumentation::InstrumentationStackFrame instrumentation_frame =
+ GetInstrumentationStackFrame(instrumentation_stack_depth);
instrumentation_stack_depth++;
- CHECK(instrumentation_frame.method_ == GetMethod()) << "Excepted: " << PrettyMethod(method)
+ if (instrumentation_frame.method_ != GetMethod()) {
+ LOG(FATAL) << "Expected: " << PrettyMethod(instrumentation_frame.method_)
<< " Found: " << PrettyMethod(GetMethod());
+ }
+ if (num_frames_ != 0) {
+ // Check agreement of frame Ids only if num_frames_ is computed to avoid infinite
+ // recursion.
+ CHECK(instrumentation_frame.frame_id_ == GetFrameId())
+ << "Expected: " << instrumentation_frame.frame_id_
+ << " Found: " << GetFrameId();
+ }
return_pc = instrumentation_frame.return_pc_;
}
}
@@ -278,13 +332,16 @@
cur_shadow_frame_ = cur_shadow_frame_->GetLink();
} while(cur_shadow_frame_ != NULL);
}
- cur_depth_++;
if (include_transitions) {
bool should_continue = VisitFrame();
if (!should_continue) {
return;
}
}
+ cur_depth_++;
+ }
+ if (num_frames_ != 0) {
+ CHECK_EQ(cur_depth_, num_frames_);
}
}