Remove Frame, merge shadow and quick representations.
Change-Id: I5ae03a5e52111792d2df7e83cbd89ab25777844b
diff --git a/src/thread.cc b/src/thread.cc
index 457de6a..0192313 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -42,7 +42,6 @@
#include "runtime_support.h"
#include "scoped_jni_thread_state.h"
#include "ScopedLocalRef.h"
-#include "shadow_frame.h"
#include "space.h"
#include "stack.h"
#include "stack_indirect_reference_table.h"
@@ -528,44 +527,10 @@
Thread::DumpState(os, this, GetTid());
}
-#if !defined(ART_USE_LLVM_COMPILER)
-void Thread::PushNativeToManagedRecord(NativeToManagedRecord* record) {
- Method **sp = top_of_managed_stack_.GetSP();
-#ifndef NDEBUG
- if (sp != NULL) {
- Method* m = *sp;
- Runtime::Current()->GetHeap()->VerifyObject(m);
- DCHECK((m == NULL) || m->IsMethod());
- }
-#endif
- record->last_top_of_managed_stack_ = reinterpret_cast<void*>(sp);
- record->last_top_of_managed_stack_pc_ = top_of_managed_stack_pc_;
- record->link_ = native_to_managed_record_;
- native_to_managed_record_ = record;
- top_of_managed_stack_.SetSP(NULL);
-}
-#else
-void Thread::PushNativeToManagedRecord(NativeToManagedRecord*) {
- LOG(FATAL) << "Called non-LLVM method with LLVM";
-}
-#endif
-
-#if !defined(ART_USE_LLVM_COMPILER)
-void Thread::PopNativeToManagedRecord(const NativeToManagedRecord& record) {
- native_to_managed_record_ = record.link_;
- top_of_managed_stack_.SetSP(reinterpret_cast<Method**>(record.last_top_of_managed_stack_));
- top_of_managed_stack_pc_ = record.last_top_of_managed_stack_pc_;
-}
-#else
-void Thread::PopNativeToManagedRecord(const NativeToManagedRecord&) {
- LOG(FATAL) << "Called non-LLVM method with LLVM";
-}
-#endif
-
-struct StackDumpVisitor : public Thread::StackVisitor {
- StackDumpVisitor(std::ostream& os, const Thread* thread)
- : last_method(NULL), last_line_number(0), repetition_count(0), os(os), thread(thread),
- frame_count(0) {
+struct StackDumpVisitor : public StackVisitor {
+ StackDumpVisitor(std::ostream& os, const Thread* thread) :
+ StackVisitor(thread->GetManagedStack(), thread->GetTraceStack()), last_method(NULL),
+ last_line_number(0), repetition_count(0), os(os), thread(thread), frame_count(0) {
}
virtual ~StackDumpVisitor() {
@@ -574,19 +539,19 @@
}
}
- bool VisitFrame(const Frame& frame, uintptr_t pc) {
- if (!frame.HasMethod()) {
+ bool VisitFrame() {
+ Method* m = GetMethod();
+ if (m->IsRuntimeMethod()) {
return true;
}
const int kMaxRepetition = 3;
- Method* m = frame.GetMethod();
Class* c = m->GetDeclaringClass();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const DexCache* dex_cache = c->GetDexCache();
int line_number = -1;
if (dex_cache != NULL) { // be tolerant of bad input
const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
- line_number = dex_file.GetLineNumFromPC(m, m->ToDexPC(pc));
+ line_number = dex_file.GetLineNumFromPC(m, GetDexPc());
}
if (line_number == last_line_number && last_method == m) {
repetition_count++;
@@ -632,7 +597,7 @@
DumpNativeStack(os, GetTid(), " native: ", false);
}
StackDumpVisitor dumper(os, this);
- WalkStack(&dumper);
+ dumper.WalkStack();
}
void Thread::SetStateWithoutSuspendCheck(ThreadState new_state) {
@@ -643,6 +608,11 @@
ThreadState Thread::SetState(ThreadState new_state) {
ThreadState old_state = state_;
+ if (old_state == kRunnable) {
+ // Non-runnable states are points where we expect thread suspension can occur.
+ AssertThreadSuspensionIsAllowable();
+ }
+
if (old_state == new_state) {
return old_state;
}
@@ -701,6 +671,7 @@
* the thread is supposed to be suspended. This is possibly faster
* on SMP and slightly more correct, but less convenient.
*/
+ AssertThreadSuspensionIsAllowable();
android_atomic_acquire_store(new_state, addr);
ANNOTATE_IGNORE_READS_BEGIN();
int suspend_count = suspend_count_;
@@ -813,35 +784,35 @@
}
Thread::Thread()
- : thin_lock_id_(0),
- tid_(0),
+ : suspend_count_(0),
+ card_table_(NULL),
+ exception_(NULL),
+ stack_end_(NULL),
+ managed_stack_(),
+ jni_env_(NULL),
+ self_(NULL),
+ state_(kNative),
peer_(NULL),
- top_of_managed_stack_(),
- top_of_managed_stack_pc_(0),
+ stack_begin_(NULL),
+ stack_size_(0),
+ thin_lock_id_(0),
+ tid_(0),
wait_mutex_(new Mutex("a thread wait mutex")),
wait_cond_(new ConditionVariable("a thread wait condition variable")),
wait_monitor_(NULL),
interrupted_(false),
wait_next_(NULL),
monitor_enter_object_(NULL),
- card_table_(0),
- stack_end_(NULL),
- native_to_managed_record_(NULL),
top_sirt_(NULL),
- top_shadow_frame_(NULL),
- jni_env_(NULL),
- state_(kNative),
- self_(NULL),
runtime_(NULL),
- exception_(NULL),
- suspend_count_(0),
- debug_suspend_count_(0),
class_loader_override_(NULL),
long_jump_context_(NULL),
throwing_OutOfMemoryError_(false),
+ debug_suspend_count_(0),
debug_invoke_req_(new DebugInvokeReq),
trace_stack_(new std::vector<TraceStackFrame>),
- name_(new std::string(kThreadNameDuringStartup)) {
+ name_(new std::string(kThreadNameDuringStartup)),
+ no_thread_suspension_(0) {
CHECK_EQ((sizeof(Thread) % 4), 0U) << sizeof(Thread);
memset(&held_mutexes_[0], 0, sizeof(held_mutexes_));
}
@@ -968,14 +939,6 @@
return count;
}
-size_t Thread::NumShadowFrameReferences() {
- size_t count = 0;
- for (ShadowFrame* cur = top_shadow_frame_; cur; cur = cur->GetLink()) {
- count += cur->NumberOfReferences();
- }
- return count;
-}
-
bool Thread::SirtContains(jobject obj) {
Object** sirt_entry = reinterpret_cast<Object**>(obj);
for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->GetLink()) {
@@ -983,21 +946,8 @@
return true;
}
}
- return false;
-}
-
-bool Thread::ShadowFrameContains(jobject obj) {
- Object** shadow_frame_entry = reinterpret_cast<Object**>(obj);
- for (ShadowFrame* cur = top_shadow_frame_; cur; cur = cur->GetLink()) {
- if (cur->Contains(shadow_frame_entry)) {
- return true;
- }
- }
- return false;
-}
-
-bool Thread::StackReferencesContain(jobject obj) {
- return SirtContains(obj) || ShadowFrameContains(obj);
+ // JNI code invoked from portable code uses shadow frames rather than the SIRT.
+ return managed_stack_.ShadowFramesContain(sirt_entry);
}
void Thread::SirtVisitRoots(Heap::RootVisitor* visitor, void* arg) {
@@ -1012,18 +962,6 @@
}
}
-void Thread::ShadowFrameVisitRoots(Heap::RootVisitor* visitor, void* arg) {
- for (ShadowFrame* cur = top_shadow_frame_; cur; cur = cur->GetLink()) {
- size_t num_refs = cur->NumberOfReferences();
- for (size_t j = 0; j < num_refs; j++) {
- Object* object = cur->GetReference(j);
- if (object != NULL) {
- visitor(object, arg);
- }
- }
- }
-}
-
Object* Thread::DecodeJObject(jobject obj) {
DCHECK(CanAccessDirectReferences());
if (obj == NULL) {
@@ -1063,7 +1001,7 @@
default:
// TODO: make stack indirect reference table lookup more efficient
// Check if this is a local reference in the SIRT
- if (StackReferencesContain(obj)) {
+ if (SirtContains(obj)) {
result = *reinterpret_cast<Object**>(obj); // Read from SIRT
} else if (Runtime::Current()->GetJavaVM()->work_around_app_jni_bugs) {
// Assume an invalid local reference is actually a direct pointer.
@@ -1083,20 +1021,24 @@
return result;
}
-class CountStackDepthVisitor : public Thread::StackVisitor {
+class CountStackDepthVisitor : public StackVisitor {
public:
- CountStackDepthVisitor() : depth_(0), skip_depth_(0), skipping_(true) {}
+ CountStackDepthVisitor(const ManagedStack* stack,
+ const std::vector<TraceStackFrame>* trace_stack) :
+ StackVisitor(stack, trace_stack), depth_(0), skip_depth_(0),
+ skipping_(true) {}
- bool VisitFrame(const Frame& frame, uintptr_t /*pc*/) {
+ bool VisitFrame() {
// We want to skip frames up to and including the exception's constructor.
// Note we also skip the frame if it doesn't have a method (namely the callee
// save frame)
- if (skipping_ && frame.HasMethod() &&
- !Throwable::GetJavaLangThrowable()->IsAssignableFrom(frame.GetMethod()->GetDeclaringClass())) {
+ Method* m = GetMethod();
+ if (skipping_ && !m->IsRuntimeMethod() &&
+ !Throwable::GetJavaLangThrowable()->IsAssignableFrom(m->GetDeclaringClass())) {
skipping_ = false;
}
if (!skipping_) {
- if (frame.HasMethod()) { // ignore callee save frames
+ if (!m->IsRuntimeMethod()) { // Ignore runtime frames (in particular callee save).
++depth_;
}
} else {
@@ -1119,90 +1061,72 @@
bool skipping_;
};
-class BuildInternalStackTraceVisitor : public Thread::StackVisitor {
+class BuildInternalStackTraceVisitor : public StackVisitor {
public:
- explicit BuildInternalStackTraceVisitor(int skip_depth)
- : skip_depth_(skip_depth), count_(0), pc_trace_(NULL), method_trace_(NULL), local_ref_(NULL) {
- }
+ explicit BuildInternalStackTraceVisitor(const ManagedStack* stack,
+ const std::vector<TraceStackFrame>* trace_stack,
+ int skip_depth) :
+ StackVisitor(stack, trace_stack), skip_depth_(skip_depth), count_(0), dex_pc_trace_(NULL),
+ method_trace_(NULL) {}
bool Init(int depth, ScopedJniThreadState& ts) {
// Allocate method trace with an extra slot that will hold the PC trace
- method_trace_ = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(depth + 1);
- if (method_trace_ == NULL) {
+ SirtRef<ObjectArray<Object> >
+ method_trace(Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(depth + 1));
+ if (method_trace.get() == NULL) {
return false;
}
- // Register a local reference as IntArray::Alloc may trigger GC
- local_ref_ = AddLocalReference<jobject>(ts.Env(), method_trace_);
- pc_trace_ = IntArray::Alloc(depth);
- if (pc_trace_ == NULL) {
+ IntArray* dex_pc_trace = IntArray::Alloc(depth);
+ if (dex_pc_trace == NULL) {
return false;
}
-#ifdef MOVING_GARBAGE_COLLECTOR
- // Re-read after potential GC
- method_trace_ = Decode<ObjectArray<Object>*>(ts.Env(), local_ref_);
-#endif
// Save PC trace in last element of method trace, also places it into the
// object graph.
- method_trace_->Set(depth, pc_trace_);
+ method_trace->Set(depth, dex_pc_trace);
+ // Set the Object*s and assert that no thread suspension is now possible.
+ ts.Self()->StartAssertNoThreadSuspension();
+ method_trace_ = method_trace.get();
+ dex_pc_trace_ = dex_pc_trace;
return true;
}
- virtual ~BuildInternalStackTraceVisitor() {}
+ virtual ~BuildInternalStackTraceVisitor() {
+ Thread::Current()->EndAssertNoThreadSuspension();
+ }
- bool VisitFrame(const Frame& frame, uintptr_t pc) {
- if (method_trace_ == NULL || pc_trace_ == NULL) {
+ bool VisitFrame() {
+ if (method_trace_ == NULL || dex_pc_trace_ == NULL) {
return true; // We're probably trying to fillInStackTrace for an OutOfMemoryError.
}
if (skip_depth_ > 0) {
skip_depth_--;
return true;
}
- if (!frame.HasMethod()) {
- return true; // ignore callee save frames
+ Method* m = GetMethod();
+ if (m->IsRuntimeMethod()) {
+ return true; // Ignore runtime frames (in particular callee save).
}
- method_trace_->Set(count_, frame.GetMethod());
- pc_trace_->Set(count_, pc);
+ method_trace_->Set(count_, m);
+ dex_pc_trace_->Set(count_, GetDexPc());
++count_;
return true;
}
- jobject GetInternalStackTrace() const {
- return local_ref_;
+ ObjectArray<Object>* GetInternalStackTrace() const {
+ return method_trace_;
}
private:
// How many more frames to skip.
int32_t skip_depth_;
- // Current position down stack trace
+ // Current position down stack trace.
uint32_t count_;
- // Array of return PC values
- IntArray* pc_trace_;
- // An array of the methods on the stack, the last entry is a reference to the
- // PC trace
+ // Array of dex PC values.
+ IntArray* dex_pc_trace_;
+ // An array of the methods on the stack, the last entry is a reference to the PC trace.
ObjectArray<Object>* method_trace_;
- // Local indirect reference table entry for method trace
- jobject local_ref_;
};
-#if !defined(ART_USE_LLVM_COMPILER)
-// TODO: remove this.
-static uintptr_t ManglePc(uintptr_t pc) {
- // Move the PC back 2 bytes as a call will frequently terminate the
- // decoding of a particular instruction and we want to make sure we
- // get the Dex PC of the instruction with the call and not the
- // instruction following.
- if (pc > 0) { pc -= 2; }
- return pc;
-}
-#endif
-
-// TODO: remove this.
-static uintptr_t DemanglePc(uintptr_t pc) {
- // Revert mangling for the case where we need the PC to return to the upcall
- if (pc > 0) { pc += 2; }
- return pc;
-}
-
void Thread::PushSirt(StackIndirectReferenceTable* sirt) {
sirt->SetLink(top_sirt_);
top_sirt_ = sirt;
@@ -1215,112 +1139,10 @@
return sirt;
}
-#if !defined(ART_USE_LLVM_COMPILER) // LLVM use ShadowFrame
-
-void Thread::WalkStack(StackVisitor* visitor, bool include_upcalls) const {
- Frame frame = GetTopOfStack();
- uintptr_t pc = ManglePc(top_of_managed_stack_pc_);
- uint32_t trace_stack_depth = 0;
- // TODO: enable this CHECK after native_to_managed_record_ is initialized during startup.
- // CHECK(native_to_managed_record_ != NULL);
- NativeToManagedRecord* record = native_to_managed_record_;
- bool method_tracing_active = Runtime::Current()->IsMethodTracingActive();
- while (frame.GetSP() != NULL) {
- for ( ; frame.GetMethod() != NULL; frame.Next()) {
- frame.GetMethod()->AssertPcIsWithinCode(pc);
- bool should_continue = visitor->VisitFrame(frame, pc);
- if (UNLIKELY(!should_continue)) {
- return;
- }
- uintptr_t return_pc = frame.GetReturnPC();
- if (LIKELY(!method_tracing_active)) {
- pc = ManglePc(return_pc);
- } else {
- // 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.
- if (IsTraceExitPc(return_pc) && !include_upcalls) {
- TraceStackFrame trace_frame = GetTraceStackFrame(trace_stack_depth++);
- CHECK(trace_frame.method_ == frame.GetMethod());
- pc = ManglePc(trace_frame.return_pc_);
- } else {
- pc = ManglePc(return_pc);
- }
- }
- }
- if (include_upcalls) {
- bool should_continue = visitor->VisitFrame(frame, pc);
- if (!should_continue) {
- return;
- }
- }
- if (record == NULL) {
- return;
- }
- // last_tos should return Frame instead of sp?
- frame.SetSP(reinterpret_cast<Method**>(record->last_top_of_managed_stack_));
- pc = ManglePc(record->last_top_of_managed_stack_pc_);
- record = record->link_;
- }
-}
-
-#else // defined(ART_USE_LLVM_COMPILER) // LLVM uses ShadowFrame
-
-void Thread::WalkStack(StackVisitor* visitor, bool /*include_upcalls*/) const {
- for (ShadowFrame* cur = top_shadow_frame_; cur; cur = cur->GetLink()) {
- Frame frame;
- frame.SetSP(reinterpret_cast<Method**>(reinterpret_cast<byte*>(cur) +
- ShadowFrame::MethodOffset()));
- bool should_continue = visitor->VisitFrame(frame, cur->GetDexPC());
- if (!should_continue) {
- return;
- }
- }
-}
-
-/*
- * | |
- * | |
- * | |
- * | . |
- * | . |
- * | . |
- * | . |
- * | Method* |
- * | . |
- * | . | <-- top_shadow_frame_ (ShadowFrame*)
- * / +------------------------+
- * ->| . |
- * . | . |
- * . | . |
- * /+------------------------+
- * / | . |
- * / | . |
- * --- | | . |
- * | | | . |
- * | | Method* | <-- frame.GetSP() (Method**)
- * ShadowFrame \ | . |
- * | ->| . | <-- cur (ShadowFrame*)
- * --- /+------------------------+
- * / | . |
- * / | . |
- * --- | | . |
- * | cur->GetLink() | | . |
- * | | Method* |
- * ShadowFrame \ | . |
- * | ->| . |
- * --- +------------------------+
- * | . |
- * | . |
- * | . |
- * +========================+
- */
-
-#endif
-
jobject Thread::CreateInternalStackTrace(JNIEnv* env) const {
// Compute depth of stack
- CountStackDepthVisitor count_visitor;
- WalkStack(&count_visitor);
+ CountStackDepthVisitor count_visitor(GetManagedStack(), GetTraceStack());
+ count_visitor.WalkStack();
int32_t depth = count_visitor.GetDepth();
int32_t skip_depth = count_visitor.GetSkipDepth();
@@ -1328,12 +1150,13 @@
ScopedJniThreadState ts(env);
// Build internal stack trace
- BuildInternalStackTraceVisitor build_trace_visitor(skip_depth);
+ BuildInternalStackTraceVisitor build_trace_visitor(GetManagedStack(), GetTraceStack(),
+ skip_depth);
if (!build_trace_visitor.Init(depth, ts)) {
return NULL; // Allocation failed
}
- WalkStack(&build_trace_visitor);
- return build_trace_visitor.GetInternalStackTrace();
+ build_trace_visitor.WalkStack();
+ return AddLocalReference<jobjectArray>(ts.Env(), build_trace_visitor.GetInternalStackTrace());
}
jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, jobject internal,
@@ -1375,8 +1198,8 @@
// Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
Method* method = down_cast<Method*>(method_trace->Get(i));
mh.ChangeMethod(method);
- uint32_t native_pc = pc_trace->Get(i);
- int32_t line_number = mh.GetLineNumFromNativePC(native_pc);
+ uint32_t dex_pc = pc_trace->Get(i);
+ int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
// Allocate element, potentially triggering GC
// TODO: reuse class_name_object via Class::name_?
const char* descriptor = mh.GetDeclaringClassDescriptor();
@@ -1609,8 +1432,8 @@
DO_THREAD_OFFSET(state_);
DO_THREAD_OFFSET(suspend_count_);
DO_THREAD_OFFSET(thin_lock_id_);
- DO_THREAD_OFFSET(top_of_managed_stack_);
- DO_THREAD_OFFSET(top_of_managed_stack_pc_);
+ //DO_THREAD_OFFSET(top_of_managed_stack_);
+ //DO_THREAD_OFFSET(top_of_managed_stack_pc_);
DO_THREAD_OFFSET(top_sirt_);
#undef DO_THREAD_OFFSET
@@ -1628,68 +1451,100 @@
os << offset;
}
-class CatchBlockStackVisitor : public Thread::StackVisitor {
+static const bool kDebugExceptionDelivery = false;
+class CatchBlockStackVisitor : public StackVisitor {
public:
- CatchBlockStackVisitor(Class* to_find, Context* ljc)
- : to_find_(to_find), long_jump_context_(ljc), native_method_count_(0),
+ CatchBlockStackVisitor(Thread* self, Throwable* exception)
+ : StackVisitor(self->GetManagedStack(), self->GetTraceStack(), self->GetLongJumpContext()),
+ self_(self), exception_(exception), to_find_(exception->GetClass()), throw_method_(NULL),
+ throw_frame_id_(0), throw_dex_pc_(0), handler_quick_frame_(NULL),
+ handler_quick_frame_pc_(0), handler_dex_pc_(0), native_method_count_(0),
method_tracing_active_(Runtime::Current()->IsMethodTracingActive()) {
-#ifndef NDEBUG
- handler_pc_ = 0xEBADC0DE;
- handler_frame_.SetSP(reinterpret_cast<Method**>(0xEBADF00D));
-#endif
+ self->StartAssertNoThreadSuspension(); // Exception not in root sets, can't allow GC.
}
- bool VisitFrame(const Frame& fr, uintptr_t pc) {
- Method* method = fr.GetMethod();
+ bool VisitFrame() {
+ Method* method = GetMethod();
if (method == NULL) {
- // This is the upcall, we remember the frame and last_pc so that we may
- // long jump to them
- handler_pc_ = DemanglePc(pc);
- handler_frame_ = fr;
+ // This is the upcall, we remember the frame and last pc so that we may long jump to them.
+ handler_quick_frame_pc_ = GetCurrentQuickFramePc();
+ handler_quick_frame_ = GetCurrentQuickFrame();
return false; // End stack walk.
}
uint32_t dex_pc = DexFile::kDexNoIndex;
if (method->IsRuntimeMethod()) {
// ignore callee save method
DCHECK(method->IsCalleeSaveMethod());
- } else if (method->IsNative()) {
- native_method_count_++;
} else {
- // Unwind stack when an exception occurs during method tracing
- if (UNLIKELY(method_tracing_active_)) {
-#if !defined(ART_USE_LLVM_COMPILER)
- if (IsTraceExitPc(DemanglePc(pc))) {
- pc = ManglePc(TraceMethodUnwindFromCode(Thread::Current()));
- }
-#else
- UNIMPLEMENTED(FATAL);
-#endif
+ if (throw_method_ == NULL) {
+ throw_method_ = method;
+ throw_frame_id_ = GetFrameId();
+ throw_dex_pc_ = GetDexPc();
}
- dex_pc = method->ToDexPC(pc);
+ if (method->IsNative()) {
+ native_method_count_++;
+ } else {
+ // Unwind stack when an exception occurs during method tracing
+ if (UNLIKELY(method_tracing_active_ && IsTraceExitPc(GetCurrentQuickFramePc()))) {
+ uintptr_t pc = AdjustQuickFramePcForDexPcComputation(TraceMethodUnwindFromCode(Thread::Current()));
+ dex_pc = method->ToDexPC(pc);
+ } else {
+ dex_pc = GetDexPc();
+ }
+ }
}
if (dex_pc != DexFile::kDexNoIndex) {
uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
if (found_dex_pc != DexFile::kDexNoIndex) {
- handler_pc_ = method->ToNativePC(found_dex_pc);
- handler_frame_ = fr;
+ handler_dex_pc_ = found_dex_pc;
+ handler_quick_frame_pc_ = method->ToNativePC(found_dex_pc);
+ handler_quick_frame_ = GetCurrentQuickFrame();
return false; // End stack walk.
}
}
-#if !defined(ART_USE_LLVM_COMPILER)
- // Caller may be handler, fill in callee saves in context
- long_jump_context_->FillCalleeSaves(fr);
-#endif
return true; // Continue stack walk.
}
- // The type of the exception catch block to find
+ void DoLongJump() {
+ Method* catch_method = *handler_quick_frame_;
+ Dbg::PostException(throw_frame_id_, throw_method_, throw_dex_pc_,
+ catch_method, handler_dex_pc_, exception_);
+ if (kDebugExceptionDelivery) {
+ if (catch_method == NULL) {
+ LOG(INFO) << "Handler is upcall";
+ } else {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile& dex_file =
+ class_linker->FindDexFile(catch_method->GetDeclaringClass()->GetDexCache());
+ int line_number = dex_file.GetLineNumFromPC(catch_method, handler_dex_pc_);
+ LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
+ }
+ }
+ self_->SetException(exception_);
+ self_->EndAssertNoThreadSuspension(); // Exception back in root set.
+ // Place context back on thread so it will be available when we continue.
+ self_->ReleaseLongJumpContext(context_);
+ context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_));
+ CHECK_NE(handler_quick_frame_pc_, 0u);
+ context_->SetPC(handler_quick_frame_pc_);
+ context_->SmashCallerSaves();
+ context_->DoLongJump();
+ }
+
+ private:
+ Thread* self_;
+ Throwable* exception_;
+ // The type of the exception catch block to find.
Class* to_find_;
- // Frame with found handler or last frame if no handler found
- Frame handler_frame_;
- // PC to branch to for the handler
- uintptr_t handler_pc_;
- // Context that will be the target of the long jump
- Context* long_jump_context_;
+ Method* throw_method_;
+ JDWP::FrameId throw_frame_id_;
+ uint32_t throw_dex_pc_;
+ // Quick frame with found handler or last frame if no handler found.
+ Method** handler_quick_frame_;
+ // PC to branch to for the handler.
+ uintptr_t handler_quick_frame_pc_;
+ // Associated dex PC.
+ uint32_t handler_dex_pc_;
// Number of native methods passed in crawl (equates to number of SIRTs to pop)
uint32_t native_method_count_;
// Is method tracing active?
@@ -1697,8 +1552,6 @@
};
void Thread::DeliverException() {
-#if !defined(ART_USE_LLVM_COMPILER)
- const bool kDebugExceptionDelivery = false;
Throwable* exception = GetException(); // Get exception from thread
CHECK(exception != NULL);
// Don't leave exception visible while we try to find the handler, which may cause class
@@ -1710,83 +1563,54 @@
DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception)
<< ": " << str_msg << "\n");
}
-
- Context* long_jump_context = GetLongJumpContext();
- CatchBlockStackVisitor catch_finder(exception->GetClass(), long_jump_context);
- WalkStack(&catch_finder, true);
-
- Method** sp;
- uintptr_t throw_native_pc;
- Method* throw_method = GetCurrentMethod(&throw_native_pc, &sp);
- uintptr_t catch_native_pc = catch_finder.handler_pc_;
- Method* catch_method = catch_finder.handler_frame_.GetMethod();
- Dbg::PostException(sp, throw_method, throw_native_pc, catch_method, catch_native_pc, exception);
-
- if (kDebugExceptionDelivery) {
- if (catch_method == NULL) {
- LOG(INFO) << "Handler is upcall";
- } else {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const DexFile& dex_file =
- class_linker->FindDexFile(catch_method->GetDeclaringClass()->GetDexCache());
- int line_number = dex_file.GetLineNumFromPC(catch_method,
- catch_method->ToDexPC(catch_finder.handler_pc_));
- LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
- }
- }
- SetException(exception);
- CHECK_NE(catch_native_pc, 0u);
- long_jump_context->SetSP(reinterpret_cast<uintptr_t>(catch_finder.handler_frame_.GetSP()));
- long_jump_context->SetPC(catch_native_pc);
- long_jump_context->SmashCallerSaves();
- long_jump_context->DoLongJump();
-#endif
+ CatchBlockStackVisitor catch_finder(this, exception);
+ catch_finder.WalkStack(true);
+ catch_finder.DoLongJump();
LOG(FATAL) << "UNREACHABLE";
}
Context* Thread::GetLongJumpContext() {
Context* result = long_jump_context_;
-#if !defined(ART_USE_LLVM_COMPILER)
if (result == NULL) {
result = Context::Create();
- long_jump_context_ = result;
+ } else {
+ long_jump_context_ = NULL; // Avoid context being shared.
}
-#endif
return result;
}
-#if !defined(ART_USE_LLVM_COMPILER)
-Method* Thread::GetCurrentMethod(uintptr_t* pc, Method*** sp) const {
- Frame f = top_of_managed_stack_;
- Method* m = f.GetMethod();
- uintptr_t native_pc = top_of_managed_stack_pc_;
+Method* Thread::GetCurrentMethod(uint32_t* dex_pc, size_t* frame_id) const {
+ struct CurrentMethodVisitor : public StackVisitor {
+ CurrentMethodVisitor(const ManagedStack* stack,
+ const std::vector<TraceStackFrame>* trace_stack) :
+ StackVisitor(stack, trace_stack), method_(NULL), dex_pc_(0), frame_id_(0) {}
- // We use JNI internally for exception throwing, so it's possible to arrive
- // here via a "FromCode" function, in which case there's a synthetic
- // callee-save method at the top of the stack. These shouldn't be user-visible,
- // so if we find one, skip it and return the compiled method underneath.
- if (m != NULL && m->IsCalleeSaveMethod()) {
- native_pc = f.GetReturnPC();
- f.Next();
- m = f.GetMethod();
+ virtual bool VisitFrame() {
+ Method* m = GetMethod();
+ if (m->IsRuntimeMethod()) {
+ // Continue if this is a runtime method.
+ return true;
+ }
+ method_ = m;
+ dex_pc_ = GetDexPc();
+ frame_id_ = GetFrameId();
+ return false;
+ }
+ Method* method_;
+ uint32_t dex_pc_;
+ size_t frame_id_;
+ };
+
+ CurrentMethodVisitor visitor(GetManagedStack(), GetTraceStack());
+ visitor.WalkStack(false);
+ if (dex_pc != NULL) {
+ *dex_pc = visitor.dex_pc_;
}
- if (pc != NULL) {
- *pc = (m != NULL) ? ManglePc(native_pc) : 0;
+ if (frame_id != NULL) {
+ *frame_id = visitor.frame_id_;
}
- if (sp != NULL) {
- *sp = f.GetSP();
- }
- return m;
+ return visitor.method_;
}
-#else
-Method* Thread::GetCurrentMethod(uintptr_t*, Method***) const {
- ShadowFrame* frame = top_shadow_frame_;
- if (frame == NULL) {
- return NULL;
- }
- return frame->GetMethod();
-}
-#endif
bool Thread::HoldsLock(Object* object) {
if (object == NULL) {
@@ -1799,65 +1623,72 @@
return DecodeField(WellKnownClasses::java_lang_Thread_daemon)->GetBoolean(peer_);
}
-#if !defined(ART_USE_LLVM_COMPILER)
-class ReferenceMapVisitor : public Thread::StackVisitor {
+class ReferenceMapVisitor : public StackVisitor {
public:
- ReferenceMapVisitor(Context* context, Heap::RootVisitor* root_visitor, void* arg) :
- context_(context), root_visitor_(root_visitor), arg_(arg) {
+ ReferenceMapVisitor(const ManagedStack* stack, const std::vector<TraceStackFrame>* trace_stack,
+ Context* context, Heap::RootVisitor* root_visitor,
+ void* arg) : StackVisitor(stack, trace_stack, context),
+ root_visitor_(root_visitor), arg_(arg) {
}
- bool VisitFrame(const Frame& frame, uintptr_t pc) {
- Method* m = frame.GetMethod();
+ bool VisitFrame() {
if (false) {
- LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m)
- << StringPrintf("@ PC:%04x", m->ToDexPC(pc));
+ LOG(INFO) << "Visiting stack roots in " << PrettyMethod(GetMethod())
+ << StringPrintf("@ PC:%04x", GetDexPc());
}
- // Process register map (which native and callee save methods don't have)
- if (!m->IsNative() && !m->IsCalleeSaveMethod() && !m->IsProxyMethod()) {
- CHECK(m->GetGcMap() != NULL) << PrettyMethod(m);
- CHECK_NE(0U, m->GetGcMapLength()) << PrettyMethod(m);
- verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
- const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
- CHECK(reg_bitmap != NULL);
- const VmapTable vmap_table(m->GetVmapTableRaw());
- const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
- DCHECK(code_item != NULL); // can't be NULL or how would we compile its instructions?
- uint32_t core_spills = m->GetCoreSpillMask();
- uint32_t fp_spills = m->GetFpSpillMask();
- size_t frame_size = m->GetFrameSizeInBytes();
- // For all dex registers in the bitmap
- size_t num_regs = std::min(map.RegWidth() * 8,
- static_cast<size_t>(code_item->registers_size_));
- for (size_t reg = 0; reg < num_regs; ++reg) {
- // Does this register hold a reference?
- if (TestBitmap(reg, reg_bitmap)) {
- uint32_t vmap_offset;
- Object* ref;
- if (vmap_table.IsInContext(reg, vmap_offset)) {
- // Compute the register we need to load from the context
- uint32_t spill_mask = m->GetCoreSpillMask();
- CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
- uint32_t matches = 0;
- uint32_t spill_shifts = 0;
- while (matches != (vmap_offset + 1)) {
- DCHECK_NE(spill_mask, 0u);
- matches += spill_mask & 1; // Add 1 if the low bit is set
- spill_mask >>= 1;
- spill_shifts++;
+ ShadowFrame* shadow_frame = GetCurrentShadowFrame();
+ if (shadow_frame != NULL) {
+ shadow_frame->VisitRoots(root_visitor_, arg_);
+ } else {
+ Method* m = GetMethod();
+ // Process register map (which native and runtime methods don't have)
+ if (!m->IsNative() && !m->IsRuntimeMethod()) {
+ const uint8_t* gc_map = m->GetGcMap();
+ CHECK(gc_map != NULL) << PrettyMethod(m);
+ uint32_t gc_map_length = m->GetGcMapLength();
+ CHECK_NE(0U, gc_map_length) << PrettyMethod(m);
+ verifier::PcToReferenceMap map(gc_map, gc_map_length);
+ const uint8_t* reg_bitmap = map.FindBitMap(GetDexPc());
+ CHECK(reg_bitmap != NULL);
+ const VmapTable vmap_table(m->GetVmapTableRaw());
+ const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+ DCHECK(code_item != NULL); // can't be NULL or how would we compile its instructions?
+ uint32_t core_spills = m->GetCoreSpillMask();
+ uint32_t fp_spills = m->GetFpSpillMask();
+ size_t frame_size = m->GetFrameSizeInBytes();
+ // For all dex registers in the bitmap
+ size_t num_regs = std::min(map.RegWidth() * 8,
+ static_cast<size_t>(code_item->registers_size_));
+ for (size_t reg = 0; reg < num_regs; ++reg) {
+ // Does this register hold a reference?
+ if (TestBitmap(reg, reg_bitmap)) {
+ uint32_t vmap_offset;
+ Object* ref;
+ if (vmap_table.IsInContext(reg, vmap_offset)) {
+ // Compute the register we need to load from the context
+ uint32_t spill_mask = core_spills;
+ CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
+ uint32_t matches = 0;
+ uint32_t spill_shifts = 0;
+ while (matches != (vmap_offset + 1)) {
+ DCHECK_NE(spill_mask, 0u);
+ matches += spill_mask & 1; // Add 1 if the low bit is set
+ spill_mask >>= 1;
+ spill_shifts++;
+ }
+ spill_shifts--; // wind back one as we want the last match
+ ref = reinterpret_cast<Object*>(GetGPR(spill_shifts));
+ } else {
+ ref = reinterpret_cast<Object*>(GetVReg(code_item, core_spills, fp_spills,
+ frame_size, reg));
}
- spill_shifts--; // wind back one as we want the last match
- ref = reinterpret_cast<Object*>(context_->GetGPR(spill_shifts));
- } else {
- ref = reinterpret_cast<Object*>(frame.GetVReg(code_item, core_spills, fp_spills,
- frame_size, reg));
- }
- if (ref != NULL) {
- root_visitor_(ref, arg_);
+ if (ref != NULL) {
+ root_visitor_(ref, arg_);
+ }
}
}
}
}
- context_->FillCalleeSaves(frame);
return true;
}
@@ -1866,14 +1697,11 @@
return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
}
- // Context used to build up picture of callee saves
- Context* context_;
// Call-back when we visit a root
Heap::RootVisitor* root_visitor_;
// Argument to call-back
void* arg_;
};
-#endif
void Thread::VisitRoots(Heap::RootVisitor* visitor, void* arg) {
if (exception_ != NULL) {
@@ -1889,29 +1717,25 @@
jni_env_->monitors.VisitRoots(visitor, arg);
SirtVisitRoots(visitor, arg);
- ShadowFrameVisitRoots(visitor, arg);
-#if !defined(ART_USE_LLVM_COMPILER)
- // Cheat and steal the long jump context. Assume that we are not doing a GC during exception
- // delivery.
- Context* context = GetLongJumpContext();
// Visit roots on this thread's stack
- ReferenceMapVisitor mapper(context, visitor, arg);
- WalkStack(&mapper);
-#endif
+ Context* context = GetLongJumpContext();
+ ReferenceMapVisitor mapper(GetManagedStack(), GetTraceStack(), context, visitor, arg);
+ mapper.WalkStack();
+ ReleaseLongJumpContext(context);
}
#if VERIFY_OBJECT_ENABLED
-static void VerifyObject(const Object* obj, void*) {
- Runtime::Current()->GetHeap()->VerifyObject(obj);
+static void VerifyObject(const Object* obj, void* arg) {
+ Heap* heap = reinterpret_cast<Heap*>(arg);
+ heap->VerifyObject(obj);
}
void Thread::VerifyStack() {
-#if !defined(ART_USE_LLVM_COMPILER)
UniquePtr<Context> context(Context::Create());
- ReferenceMapVisitor mapper(context.get(), VerifyObject, NULL);
- WalkStack(&mapper);
-#endif
+ ReferenceMapVisitor mapper(GetManagedStack(), context.get(), VerifyObject,
+ Runtime::Current()->GetHeap());
+ mapper.WalkStack();
}
#endif