diff options
| -rw-r--r-- | src/dalvik_system_VMStack.cc | 11 | ||||
| -rw-r--r-- | src/debugger.cc | 42 | ||||
| -rw-r--r-- | src/debugger.h | 2 | ||||
| -rw-r--r-- | src/jdwp/jdwp_handler.cc | 2 | ||||
| -rw-r--r-- | src/thread.cc | 130 | ||||
| -rw-r--r-- | src/thread.h | 7 | ||||
| -rw-r--r-- | test/ReferenceMap/stack_walk_refmap_jni.cc | 10 | ||||
| -rw-r--r-- | test/StackWalk/stack_walk_jni.cc | 6 |
8 files changed, 98 insertions, 112 deletions
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc index bcfe29b583..a83ad454bf 100644 --- a/src/dalvik_system_VMStack.cc +++ b/src/dalvik_system_VMStack.cc @@ -59,18 +59,15 @@ jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBoots struct ClosestUserClassLoaderVisitor : public Thread::StackVisitor { ClosestUserClassLoaderVisitor(Object* bootstrap, Object* system) : bootstrap(bootstrap), system(system), class_loader(NULL) {} - virtual void VisitFrame(const Frame& f, uintptr_t) { - if (class_loader != NULL) { - // If we already found a result, nothing to do. - // TODO: need SmartFrame (Thread::WalkStack-like iterator). - // (or change VisitFrame to let us return bool to stop visiting) - return; - } + bool VisitFrame(const Frame& f, uintptr_t) { + DCHECK(class_loader == NULL); Class* c = f.GetMethod()->GetDeclaringClass(); Object* cl = c->GetClassLoader(); if (cl != NULL && cl != bootstrap && cl != system) { class_loader = cl; + return false; } + return true; } Object* bootstrap; Object* system; diff --git a/src/debugger.cc b/src/debugger.cc index 1480ee7338..025577516f 100644 --- a/src/debugger.cc +++ b/src/debugger.cc @@ -1468,11 +1468,11 @@ void Dbg::GetAllThreads(JDWP::ObjectId** ppThreadIds, uint32_t* pThreadCount) { static int GetStackDepth(Thread* thread) { struct CountStackDepthVisitor : public Thread::StackVisitor { CountStackDepthVisitor() : depth(0) {} - virtual void VisitFrame(const Frame& f, uintptr_t) { - // TODO: we'll need to skip callee-save frames too. + bool VisitFrame(const Frame& f, uintptr_t) { if (f.HasMethod()) { ++depth; } + return true; } size_t depth; }; @@ -1486,30 +1486,24 @@ int Dbg::GetThreadFrameCount(JDWP::ObjectId threadId) { return GetStackDepth(DecodeThread(threadId)); } -bool Dbg::GetThreadFrame(JDWP::ObjectId threadId, int desired_frame_number, JDWP::FrameId* pFrameId, JDWP::JdwpLocation* pLoc) { +void Dbg::GetThreadFrame(JDWP::ObjectId threadId, int desired_frame_number, JDWP::FrameId* pFrameId, JDWP::JdwpLocation* pLoc) { ScopedThreadListLock thread_list_lock; struct GetFrameVisitor : public Thread::StackVisitor { GetFrameVisitor(int desired_frame_number, JDWP::FrameId* pFrameId, JDWP::JdwpLocation* pLoc) - : found(false), depth(0), desired_frame_number(desired_frame_number), pFrameId(pFrameId), pLoc(pLoc) { + : depth(0), desired_frame_number(desired_frame_number), pFrameId(pFrameId), pLoc(pLoc) { } - virtual void VisitFrame(const Frame& f, uintptr_t pc) { - if (found) { - return; - } - - // TODO: we'll need to skip callee-save frames too. + bool VisitFrame(const Frame& f, uintptr_t pc) { if (!f.HasMethod()) { - return; // The debugger can't do anything useful with a frame that has no Method*. + return true; // The debugger can't do anything useful with a frame that has no Method*. } - if (depth == desired_frame_number) { *pFrameId = reinterpret_cast<JDWP::FrameId>(f.GetSP()); SetLocation(*pLoc, f.GetMethod(), pc); - found = true; + return false; } ++depth; + return true; } - bool found; int depth; int desired_frame_number; JDWP::FrameId* pFrameId; @@ -1518,7 +1512,6 @@ bool Dbg::GetThreadFrame(JDWP::ObjectId threadId, int desired_frame_number, JDWP GetFrameVisitor visitor(desired_frame_number, pFrameId, pLoc); visitor.desired_frame_number = desired_frame_number; DecodeThread(threadId)->WalkStack(&visitor); - return visitor.found; } JDWP::ObjectId Dbg::GetThreadSelfId() { @@ -1940,8 +1933,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId threadId, JDWP::JdwpStepSize s gSingleStepControl.method = NULL; gSingleStepControl.stack_depth = 0; } - virtual void VisitFrame(const Frame& f, uintptr_t pc) { - // TODO: we'll need to skip callee-save frames too. + bool VisitFrame(const Frame& f, uintptr_t pc) { if (f.HasMethod()) { ++gSingleStepControl.stack_depth; if (gSingleStepControl.method == NULL) { @@ -1955,6 +1947,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId threadId, JDWP::JdwpStepSize s } } } + return true; } }; SingleStepStackVisitor visitor; @@ -2840,17 +2833,16 @@ struct AllocRecordStackVisitor : public Thread::StackVisitor { explicit AllocRecordStackVisitor(AllocRecord* record) : record(record), depth(0) { } - virtual void VisitFrame(const Frame& f, uintptr_t pc) { + bool VisitFrame(const Frame& f, uintptr_t pc) { if (depth >= kMaxAllocRecordStackDepth) { - return; + return false; } - Method* m = f.GetMethod(); - if (m == NULL || m->IsCalleeSaveMethod()) { - return; + if (f.HasMethod()) { + record->stack[depth].method = f.GetMethod(); + record->stack[depth].raw_pc = pc; + ++depth; } - record->stack[depth].method = m; - record->stack[depth].raw_pc = pc; - ++depth; + return true; } ~AllocRecordStackVisitor() { diff --git a/src/debugger.h b/src/debugger.h index 659843ac87..fac97053ef 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -193,7 +193,7 @@ class Dbg { static void GetThreadGroupThreads(JDWP::ObjectId threadGroupId, JDWP::ObjectId** ppThreadIds, uint32_t* pThreadCount); static void GetAllThreads(JDWP::ObjectId** ppThreadIds, uint32_t* pThreadCount); static int GetThreadFrameCount(JDWP::ObjectId threadId); - static bool GetThreadFrame(JDWP::ObjectId threadId, int num, JDWP::FrameId* pFrameId, JDWP::JdwpLocation* pLoc); + static void GetThreadFrame(JDWP::ObjectId threadId, int num, JDWP::FrameId* pFrameId, JDWP::JdwpLocation* pLoc); static JDWP::ObjectId GetThreadSelfId(); static void SuspendVM(); diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc index 284ca64df3..9fb8ad061f 100644 --- a/src/jdwp/jdwp_handler.cc +++ b/src/jdwp/jdwp_handler.cc @@ -976,6 +976,8 @@ static JdwpError handleTR_Frames(JdwpState* state, const uint8_t* buf, int dataL for (uint32_t i = start_frame; i < (start_frame + length); ++i) { FrameId frameId; JdwpLocation loc; + // TODO: switch to GetThreadFrames so we don't have to search for each frame + // even though we only want them in order. Dbg::GetThreadFrame(threadId, i, &frameId, &loc); expandBufAdd8BE(pReply, frameId); diff --git a/src/thread.cc b/src/thread.cc index 8470b8ded4..b511aa75bc 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -566,9 +566,9 @@ struct StackDumpVisitor : public Thread::StackVisitor { virtual ~StackDumpVisitor() { } - void VisitFrame(const Frame& frame, uintptr_t pc) { + bool VisitFrame(const Frame& frame, uintptr_t pc) { if (!frame.HasMethod()) { - return; + return true; } const int kMaxRepetition = 3; Method* m = frame.GetMethod(); @@ -606,6 +606,7 @@ struct StackDumpVisitor : public Thread::StackVisitor { if (frame_count++ == 0) { Monitor::DescribeWait(os, thread); } + return true; } MethodHelper mh; Method* last_method; @@ -1066,7 +1067,7 @@ class CountStackDepthVisitor : public Thread::StackVisitor { public: CountStackDepthVisitor() : depth_(0), skip_depth_(0), skipping_(true) {} - virtual void VisitFrame(const Frame& frame, uintptr_t pc) { + bool VisitFrame(const Frame& frame, uintptr_t pc) { // 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) @@ -1081,6 +1082,7 @@ class CountStackDepthVisitor : public Thread::StackVisitor { } else { ++skip_depth_; } + return true; } int GetDepth() const { @@ -1127,20 +1129,21 @@ class BuildInternalStackTraceVisitor : public Thread::StackVisitor { virtual ~BuildInternalStackTraceVisitor() {} - virtual void VisitFrame(const Frame& frame, uintptr_t pc) { + bool VisitFrame(const Frame& frame, uintptr_t pc) { if (method_trace_ == NULL || pc_trace_ == NULL) { - return; // We're probably trying to fillInStackTrace for an OutOfMemoryError. + return true; // We're probably trying to fillInStackTrace for an OutOfMemoryError. } if (skip_depth_ > 0) { skip_depth_--; - return; + return true; } if (!frame.HasMethod()) { - return; // ignore callee save frames + return true; // ignore callee save frames } method_trace_->Set(count_, frame.GetMethod()); pc_trace_->Set(count_, pc); ++count_; + return true; } jobject GetInternalStackTrace() const { @@ -1190,7 +1193,7 @@ StackIndirectReferenceTable* Thread::PopSirt() { return sirt; } -void Thread::WalkStack(StackVisitor* visitor) const { +void Thread::WalkStack(StackVisitor* visitor, bool include_upcalls) const { Frame frame = GetTopOfStack(); uintptr_t pc = ManglePc(top_of_managed_stack_pc_); #if defined(__arm__) @@ -1200,10 +1203,13 @@ void Thread::WalkStack(StackVisitor* visitor) const { // CHECK(native_to_managed_record_ != NULL); NativeToManagedRecord* record = native_to_managed_record_; - while (frame.GetSP() != 0) { - for ( ; frame.GetMethod() != 0; frame.Next()) { + while (frame.GetSP() != NULL) { + for ( ; frame.GetMethod() != NULL; frame.Next()) { // DCHECK(frame.GetMethod()->IsWithinCode(pc)); // TODO: restore IsWithinCode - visitor->VisitFrame(frame, pc); + bool should_continue = visitor->VisitFrame(frame, pc); + if (!should_continue) { + return; + } pc = ManglePc(frame.GetReturnPC()); if (Runtime::Current()->IsMethodTracingActive()) { #if defined(__arm__) @@ -1216,8 +1222,14 @@ void Thread::WalkStack(StackVisitor* visitor) const { #endif } } + if (include_upcalls) { + bool should_continue = visitor->VisitFrame(frame, pc); + if (!should_continue) { + return; + } + } if (record == NULL) { - break; + return; } // last_tos should return Frame instead of sp? frame.SetSP(reinterpret_cast<Method**>(record->last_top_of_managed_stack_)); @@ -1226,22 +1238,6 @@ void Thread::WalkStack(StackVisitor* visitor) const { } } -void Thread::WalkStackUntilUpCall(StackVisitor* visitor, bool include_upcall) const { - Frame frame = GetTopOfStack(); - uintptr_t pc = ManglePc(top_of_managed_stack_pc_); - - if (frame.GetSP() != 0) { - for ( ; frame.GetMethod() != 0; frame.Next()) { - // DCHECK(frame.GetMethod()->IsWithinCode(pc)); // TODO: restore IsWithinCode - visitor->VisitFrame(frame, pc); - pc = ManglePc(frame.GetReturnPC()); - } - if (include_upcall) { - visitor->VisitFrame(frame, pc); - } - } -} - jobject Thread::CreateInternalStackTrace(JNIEnv* env) const { // Compute depth of stack CountStackDepthVisitor count_visitor; @@ -1430,59 +1426,54 @@ void Thread::DumpFromGdb() const { class CatchBlockStackVisitor : public Thread::StackVisitor { public: CatchBlockStackVisitor(Class* to_find, Context* ljc) - : found_(false), to_find_(to_find), long_jump_context_(ljc), native_method_count_(0) { + : to_find_(to_find), long_jump_context_(ljc), native_method_count_(0) { #ifndef NDEBUG handler_pc_ = 0xEBADC0DE; handler_frame_.SetSP(reinterpret_cast<Method**>(0xEBADF00D)); #endif } - virtual void VisitFrame(const Frame& fr, uintptr_t pc) { - if (!found_) { - Method* method = fr.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; - return; - } - uint32_t dex_pc = DexFile::kDexNoIndex; - if (method->IsCalleeSaveMethod()) { - // ignore callee save method - } else if (method->IsNative()) { - native_method_count_++; - } else { - // Unwind stack during method tracing - if (Runtime::Current()->IsMethodTracingActive()) { + bool VisitFrame(const Frame& fr, uintptr_t pc) { + Method* method = fr.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; + return false; + } + uint32_t dex_pc = DexFile::kDexNoIndex; + if (method->IsCalleeSaveMethod()) { + // ignore callee save method + } else if (method->IsNative()) { + native_method_count_++; + } else { + // Unwind stack during method tracing + if (Runtime::Current()->IsMethodTracingActive()) { #if defined(__arm__) - uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code); - if (ManglePc(trace_exit) == pc) { - pc = ManglePc(TraceMethodUnwindFromCode(Thread::Current())); - } + uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code); + if (ManglePc(trace_exit) == pc) { + pc = ManglePc(TraceMethodUnwindFromCode(Thread::Current())); + } #else - UNIMPLEMENTED(WARNING); + UNIMPLEMENTED(WARNING); #endif - } - dex_pc = method->ToDexPC(pc); - } - if (dex_pc != DexFile::kDexNoIndex) { - uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc); - if (found_dex_pc != DexFile::kDexNoIndex) { - found_ = true; - handler_pc_ = method->ToNativePC(found_dex_pc); - handler_frame_ = fr; - } } - if (!found_) { - // Caller may be handler, fill in callee saves in context - long_jump_context_->FillCalleeSaves(fr); + dex_pc = method->ToDexPC(pc); + } + 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; + return false; } } + // Caller may be handler, fill in callee saves in context + long_jump_context_->FillCalleeSaves(fr); + return true; } - // Did we find a catch block yet? - bool found_; // The type of the exception catch block to find Class* to_find_; // Frame with found handler or last frame if no handler found @@ -1511,7 +1502,7 @@ void Thread::DeliverException() { Context* long_jump_context = GetLongJumpContext(); CatchBlockStackVisitor catch_finder(exception->GetClass(), long_jump_context); - WalkStackUntilUpCall(&catch_finder, true); + WalkStack(&catch_finder, true); Method** sp; uintptr_t throw_native_pc; @@ -1589,7 +1580,7 @@ class ReferenceMapVisitor : public Thread::StackVisitor { context_(context), root_visitor_(root_visitor), arg_(arg) { } - void VisitFrame(const Frame& frame, uintptr_t pc) { + bool VisitFrame(const Frame& frame, uintptr_t pc) { Method* m = frame.GetMethod(); if (false) { LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m, false) @@ -1641,6 +1632,7 @@ class ReferenceMapVisitor : public Thread::StackVisitor { } } context_->FillCalleeSaves(frame); + return true; } private: diff --git a/src/thread.h b/src/thread.h index 94659c411a..51385f9b22 100644 --- a/src/thread.h +++ b/src/thread.h @@ -92,7 +92,8 @@ class PACKED Thread { class StackVisitor { public: virtual ~StackVisitor() {} - virtual void VisitFrame(const Frame& frame, uintptr_t pc) = 0; + // Return 'true' if we should continue to visit more frames, 'false' to stop. + virtual bool VisitFrame(const Frame& frame, uintptr_t pc) = 0; }; // Creates a new thread. @@ -399,7 +400,7 @@ class PACKED Thread { return ThreadOffset(OFFSETOF_MEMBER(Thread, top_sirt_)); } - void WalkStack(StackVisitor* visitor) const; + void WalkStack(StackVisitor* visitor, bool include_upcalls = false) const; DebugInvokeReq* GetInvokeReq() { return debug_invoke_req_; @@ -463,8 +464,6 @@ class PACKED Thread { static void ThreadExitCallback(void* arg); - void WalkStackUntilUpCall(StackVisitor* visitor, bool include_upcall) const; - // Thin lock thread id. This is a small integer used by the thin lock implementation. // This is not to be confused with the native thread's tid, nor is it the value returned // by java.lang.Thread.getId --- this is a distinct value, used only for locking. One diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc index b3f82db1e5..f6d4ac3086 100644 --- a/test/ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/ReferenceMap/stack_walk_refmap_jni.cc @@ -43,10 +43,10 @@ struct ReferenceMap2Visitor : public Thread::StackVisitor { ReferenceMap2Visitor() { } - void VisitFrame(const Frame& frame, uintptr_t pc) { + bool VisitFrame(const Frame& frame, uintptr_t pc) { Method* m = frame.GetMethod(); if (!m || m->IsNative()) { - return; + return true; } LOG(INFO) << "At " << PrettyMethod(m, false); @@ -54,11 +54,11 @@ struct ReferenceMap2Visitor : public Thread::StackVisitor { if (!pc) { // pc == NULL: m is either a native method or a phony method - return; + return true; } if (m->IsCalleeSaveMethod()) { LOG(WARNING) << "no PC for " << PrettyMethod(m); - return; + return true; } // Enable this to dump reference map to LOG(INFO) @@ -156,6 +156,8 @@ struct ReferenceMap2Visitor : public Thread::StackVisitor { CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0); // v8: this, v3: y, v2: y, v1: x, v0: ex } + + return true; } }; diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc index 69b4837e39..65b3284b22 100644 --- a/test/StackWalk/stack_walk_jni.cc +++ b/test/StackWalk/stack_walk_jni.cc @@ -42,7 +42,7 @@ struct ReferenceMapVisitor : public Thread::StackVisitor { ReferenceMapVisitor() { } - void VisitFrame(const Frame& frame, uintptr_t pc) { + bool VisitFrame(const Frame& frame, uintptr_t pc) { Method* m = frame.GetMethod(); CHECK(m != NULL); LOG(INFO) << "At " << PrettyMethod(m, false); @@ -50,7 +50,7 @@ struct ReferenceMapVisitor : public Thread::StackVisitor { if (m->IsCalleeSaveMethod() || m->IsNative()) { LOG(WARNING) << "no PC for " << PrettyMethod(m); CHECK_EQ(pc, 0u); - return; + return true; } verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength()); const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc)); @@ -89,6 +89,8 @@ struct ReferenceMapVisitor : public Thread::StackVisitor { } } LOG(INFO) << reinterpret_cast<const void*>(reg_bitmap); + + return true; } }; |