summaryrefslogtreecommitdiff
path: root/runtime/debugger.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/debugger.cc')
-rw-r--r--runtime/debugger.cc528
1 files changed, 311 insertions, 217 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 39980f000a..3ad7fc92a2 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2362,18 +2362,25 @@ void Dbg::GetThreads(mirror::Object* thread_group, std::vector<JDWP::ObjectId>*
}
static int GetStackDepth(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_) {
- size_t depth = 0u;
- StackVisitor::WalkStack(
- [&depth](const StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!visitor->GetMethod()->IsRuntimeMethod()) {
- ++depth;
- }
- return true;
- },
- thread,
- /* context= */ nullptr,
- StackVisitor::StackWalkKind::kIncludeInlinedFrames);
- return depth;
+ struct CountStackDepthVisitor : public StackVisitor {
+ explicit CountStackDepthVisitor(Thread* thread_in)
+ : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ depth(0) {}
+
+ // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
+ // annotalysis.
+ bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
+ if (!GetMethod()->IsRuntimeMethod()) {
+ ++depth;
+ }
+ return true;
+ }
+ size_t depth;
+ };
+
+ CountStackDepthVisitor visitor(thread);
+ visitor.WalkStack();
+ return visitor.depth;
}
JDWP::JdwpError Dbg::GetThreadFrameCount(JDWP::ObjectId thread_id, size_t* result) {
@@ -2391,10 +2398,47 @@ JDWP::JdwpError Dbg::GetThreadFrameCount(JDWP::ObjectId thread_id, size_t* resul
return JDWP::ERR_NONE;
}
-JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id,
- const size_t start_frame,
- const size_t frame_count,
- JDWP::ExpandBuf* buf) {
+JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_frame,
+ size_t frame_count, JDWP::ExpandBuf* buf) {
+ class GetFrameVisitor : public StackVisitor {
+ public:
+ GetFrameVisitor(Thread* thread, size_t start_frame_in, size_t frame_count_in,
+ JDWP::ExpandBuf* buf_in)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ depth_(0),
+ start_frame_(start_frame_in),
+ frame_count_(frame_count_in),
+ buf_(buf_in) {
+ expandBufAdd4BE(buf_, frame_count_);
+ }
+
+ bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (GetMethod()->IsRuntimeMethod()) {
+ return true; // The debugger can't do anything useful with a frame that has no Method*.
+ }
+ if (depth_ >= start_frame_ + frame_count_) {
+ return false;
+ }
+ if (depth_ >= start_frame_) {
+ JDWP::FrameId frame_id(GetFrameId());
+ JDWP::JdwpLocation location;
+ SetJdwpLocation(&location, GetMethod(), GetDexPc());
+ VLOG(jdwp) << StringPrintf(" Frame %3zd: id=%3" PRIu64 " ", depth_, frame_id) << location;
+ expandBufAdd8BE(buf_, frame_id);
+ expandBufAddLocation(buf_, location);
+ }
+ ++depth_;
+ return true;
+ }
+
+ private:
+ size_t depth_;
+ const size_t start_frame_;
+ const size_t frame_count_;
+ JDWP::ExpandBuf* buf_;
+ };
+
ScopedObjectAccessUnchecked soa(Thread::Current());
JDWP::JdwpError error;
Thread* thread = DecodeThread(soa, thread_id, &error);
@@ -2404,32 +2448,8 @@ JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id,
if (!IsSuspendedForDebugger(soa, thread)) {
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
-
- size_t depth = 0u;
- StackVisitor::WalkStack(
- [&](StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (visitor->GetMethod()->IsRuntimeMethod()) {
- return true; // The debugger can't do anything useful with a frame that has no Method*.
- }
- if (depth >= start_frame + frame_count) {
- return false;
- }
- if (depth >= start_frame) {
- JDWP::FrameId frame_id(visitor->GetFrameId());
- JDWP::JdwpLocation location;
- SetJdwpLocation(&location, visitor->GetMethod(), visitor->GetDexPc());
- VLOG(jdwp)
- << StringPrintf(" Frame %3zd: id=%3" PRIu64 " ", depth, frame_id) << location;
- expandBufAdd8BE(buf, frame_id);
- expandBufAddLocation(buf, location);
- }
- ++depth;
- return true;
- },
- thread,
- /* context= */ nullptr,
- StackVisitor::StackWalkKind::kIncludeInlinedFrames);
-
+ GetFrameVisitor visitor(thread, start_frame, frame_count, buf);
+ visitor.WalkStack();
return JDWP::ERR_NONE;
}
@@ -2510,6 +2530,28 @@ void Dbg::SuspendSelf() {
Runtime::Current()->GetThreadList()->SuspendSelfForDebugger();
}
+struct GetThisVisitor : public StackVisitor {
+ GetThisVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id_in)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ this_object(nullptr),
+ frame_id(frame_id_in) {}
+
+ // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
+ // annotalysis.
+ bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
+ if (frame_id != GetFrameId()) {
+ return true; // continue
+ } else {
+ this_object = GetThisObject();
+ return false;
+ }
+ }
+
+ mirror::Object* this_object;
+ JDWP::FrameId frame_id;
+};
+
JDWP::JdwpError Dbg::GetThisObject(JDWP::ObjectId thread_id, JDWP::FrameId frame_id,
JDWP::ObjectId* result) {
ScopedObjectAccessUnchecked soa(Thread::Current());
@@ -2522,50 +2564,48 @@ JDWP::JdwpError Dbg::GetThisObject(JDWP::ObjectId thread_id, JDWP::FrameId frame
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
std::unique_ptr<Context> context(Context::Create());
- mirror::Object* this_object = nullptr;
- StackVisitor::WalkStack(
- [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (frame_id != stack_visitor->GetFrameId()) {
- return true; // continue
- } else {
- this_object = stack_visitor->GetThisObject();
- return false;
- }
- },
- thread,
- context.get(),
- art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
- *result = gRegistry->Add(this_object);
+ GetThisVisitor visitor(thread, context.get(), frame_id);
+ visitor.WalkStack();
+ *result = gRegistry->Add(visitor.this_object);
return JDWP::ERR_NONE;
}
-template <typename FrameHandler>
-static JDWP::JdwpError FindAndHandleNonNativeFrame(Thread* thread,
- JDWP::FrameId frame_id,
- const FrameHandler& handler)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- JDWP::JdwpError result = JDWP::ERR_INVALID_FRAMEID;
- std::unique_ptr<Context> context(Context::Create());
- StackVisitor::WalkStack(
- [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (stack_visitor->GetFrameId() != frame_id) {
- return true; // Not our frame, carry on.
- }
- ArtMethod* m = stack_visitor->GetMethod();
- if (m->IsNative()) {
- // We can't read/write local value from/into native method.
- result = JDWP::ERR_OPAQUE_FRAME;
- } else {
- // We found our frame.
- result = handler(stack_visitor);
- }
- return false;
- },
- thread,
- context.get(),
- art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
- return result;
-}
+// Walks the stack until we find the frame with the given FrameId.
+class FindFrameVisitor final : public StackVisitor {
+ public:
+ FindFrameVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ frame_id_(frame_id),
+ error_(JDWP::ERR_INVALID_FRAMEID) {}
+
+ // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
+ // annotalysis.
+ bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
+ if (GetFrameId() != frame_id_) {
+ return true; // Not our frame, carry on.
+ }
+ ArtMethod* m = GetMethod();
+ if (m->IsNative()) {
+ // We can't read/write local value from/into native method.
+ error_ = JDWP::ERR_OPAQUE_FRAME;
+ } else {
+ // We found our frame.
+ error_ = JDWP::ERR_NONE;
+ }
+ return false;
+ }
+
+ JDWP::JdwpError GetError() const {
+ return error_;
+ }
+
+ private:
+ const JDWP::FrameId frame_id_;
+ JDWP::JdwpError error_;
+
+ DISALLOW_COPY_AND_ASSIGN(FindFrameVisitor);
+};
JDWP::JdwpError Dbg::GetLocalValues(JDWP::Request* request, JDWP::ExpandBuf* pReply) {
JDWP::ObjectId thread_id = request->ReadThreadId();
@@ -2580,29 +2620,31 @@ JDWP::JdwpError Dbg::GetLocalValues(JDWP::Request* request, JDWP::ExpandBuf* pRe
if (!IsSuspendedForDebugger(soa, thread)) {
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
+ // Find the frame with the given frame_id.
+ std::unique_ptr<Context> context(Context::Create());
+ FindFrameVisitor visitor(thread, context.get(), frame_id);
+ visitor.WalkStack();
+ if (visitor.GetError() != JDWP::ERR_NONE) {
+ return visitor.GetError();
+ }
- return FindAndHandleNonNativeFrame(
- thread,
- frame_id,
- [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Read the values from visitor's context.
- int32_t slot_count = request->ReadSigned32("slot count");
- expandBufAdd4BE(pReply, slot_count); /* "int values" */
- for (int32_t i = 0; i < slot_count; ++i) {
- uint32_t slot = request->ReadUnsigned32("slot");
- JDWP::JdwpTag reqSigByte = request->ReadTag();
+ // Read the values from visitor's context.
+ int32_t slot_count = request->ReadSigned32("slot count");
+ expandBufAdd4BE(pReply, slot_count); /* "int values" */
+ for (int32_t i = 0; i < slot_count; ++i) {
+ uint32_t slot = request->ReadUnsigned32("slot");
+ JDWP::JdwpTag reqSigByte = request->ReadTag();
- VLOG(jdwp) << " --> slot " << slot << " " << reqSigByte;
+ VLOG(jdwp) << " --> slot " << slot << " " << reqSigByte;
- size_t width = Dbg::GetTagWidth(reqSigByte);
- uint8_t* ptr = expandBufAddSpace(pReply, width + 1);
- error = Dbg::GetLocalValue(*stack_visitor, soa, slot, reqSigByte, ptr, width);
- if (error != JDWP::ERR_NONE) {
- return error;
- }
- }
- return JDWP::ERR_NONE;
- });
+ size_t width = Dbg::GetTagWidth(reqSigByte);
+ uint8_t* ptr = expandBufAddSpace(pReply, width + 1);
+ error = Dbg::GetLocalValue(visitor, soa, slot, reqSigByte, ptr, width);
+ if (error != JDWP::ERR_NONE) {
+ return error;
+ }
+ }
+ return JDWP::ERR_NONE;
}
constexpr JDWP::JdwpError kStackFrameLocalAccessError = JDWP::ERR_ABSENT_INFORMATION;
@@ -2749,27 +2791,29 @@ JDWP::JdwpError Dbg::SetLocalValues(JDWP::Request* request) {
if (!IsSuspendedForDebugger(soa, thread)) {
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
+ // Find the frame with the given frame_id.
+ std::unique_ptr<Context> context(Context::Create());
+ FindFrameVisitor visitor(thread, context.get(), frame_id);
+ visitor.WalkStack();
+ if (visitor.GetError() != JDWP::ERR_NONE) {
+ return visitor.GetError();
+ }
- return FindAndHandleNonNativeFrame(
- thread,
- frame_id,
- [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Writes the values into visitor's context.
- int32_t slot_count = request->ReadSigned32("slot count");
- for (int32_t i = 0; i < slot_count; ++i) {
- uint32_t slot = request->ReadUnsigned32("slot");
- JDWP::JdwpTag sigByte = request->ReadTag();
- size_t width = Dbg::GetTagWidth(sigByte);
- uint64_t value = request->ReadValue(width);
-
- VLOG(jdwp) << " --> slot " << slot << " " << sigByte << " " << value;
- error = Dbg::SetLocalValue(thread, *stack_visitor, slot, sigByte, value, width);
- if (error != JDWP::ERR_NONE) {
- return error;
- }
- }
- return JDWP::ERR_NONE;
- });
+ // Writes the values into visitor's context.
+ int32_t slot_count = request->ReadSigned32("slot count");
+ for (int32_t i = 0; i < slot_count; ++i) {
+ uint32_t slot = request->ReadUnsigned32("slot");
+ JDWP::JdwpTag sigByte = request->ReadTag();
+ size_t width = Dbg::GetTagWidth(sigByte);
+ uint64_t value = request->ReadValue(width);
+
+ VLOG(jdwp) << " --> slot " << slot << " " << sigByte << " " << value;
+ error = Dbg::SetLocalValue(thread, visitor, slot, sigByte, value, width);
+ if (error != JDWP::ERR_NONE) {
+ return error;
+ }
+ }
+ return JDWP::ERR_NONE;
}
template<typename T>
@@ -2941,71 +2985,107 @@ void Dbg::PostFieldModificationEvent(ArtMethod* m, int dex_pc,
gJdwpState->PostFieldEvent(&location, f, this_object, field_value, true);
}
+/**
+ * Finds the location where this exception will be caught. We search until we reach the top
+ * frame, in which case this exception is considered uncaught.
+ */
+class CatchLocationFinder : public StackVisitor {
+ public:
+ CatchLocationFinder(Thread* self, const Handle<mirror::Throwable>& exception, Context* context)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : StackVisitor(self, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ exception_(exception),
+ handle_scope_(self),
+ this_at_throw_(handle_scope_.NewHandle<mirror::Object>(nullptr)),
+ catch_method_(nullptr),
+ throw_method_(nullptr),
+ catch_dex_pc_(dex::kDexNoIndex),
+ throw_dex_pc_(dex::kDexNoIndex) {
+ }
+
+ bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* method = GetMethod();
+ DCHECK(method != nullptr);
+ if (method->IsRuntimeMethod()) {
+ // Ignore callee save method.
+ DCHECK(method->IsCalleeSaveMethod());
+ return true;
+ }
+
+ uint32_t dex_pc = GetDexPc();
+ if (throw_method_ == nullptr) {
+ // First Java method found. It is either the method that threw the exception,
+ // or the Java native method that is reporting an exception thrown by
+ // native code.
+ this_at_throw_.Assign(GetThisObject());
+ throw_method_ = method;
+ throw_dex_pc_ = dex_pc;
+ }
+
+ if (dex_pc != dex::kDexNoIndex) {
+ StackHandleScope<1> hs(GetThread());
+ uint32_t found_dex_pc;
+ Handle<mirror::Class> exception_class(hs.NewHandle(exception_->GetClass()));
+ bool unused_clear_exception;
+ found_dex_pc = method->FindCatchBlock(exception_class, dex_pc, &unused_clear_exception);
+ if (found_dex_pc != dex::kDexNoIndex) {
+ catch_method_ = method;
+ catch_dex_pc_ = found_dex_pc;
+ return false; // End stack walk.
+ }
+ }
+ return true; // Continue stack walk.
+ }
+
+ ArtMethod* GetCatchMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return catch_method_;
+ }
+
+ ArtMethod* GetThrowMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return throw_method_;
+ }
+
+ mirror::Object* GetThisAtThrow() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return this_at_throw_.Get();
+ }
+
+ uint32_t GetCatchDexPc() const {
+ return catch_dex_pc_;
+ }
+
+ uint32_t GetThrowDexPc() const {
+ return throw_dex_pc_;
+ }
+
+ private:
+ const Handle<mirror::Throwable>& exception_;
+ StackHandleScope<1> handle_scope_;
+ MutableHandle<mirror::Object> this_at_throw_;
+ ArtMethod* catch_method_;
+ ArtMethod* throw_method_;
+ uint32_t catch_dex_pc_;
+ uint32_t throw_dex_pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
+};
+
void Dbg::PostException(mirror::Throwable* exception_object) {
if (!IsDebuggerActive()) {
return;
}
Thread* const self = Thread::Current();
- StackHandleScope<2> handle_scope(self);
+ StackHandleScope<1> handle_scope(self);
Handle<mirror::Throwable> h_exception(handle_scope.NewHandle(exception_object));
- MutableHandle<mirror::Object> this_at_throw = handle_scope.NewHandle<mirror::Object>(nullptr);
std::unique_ptr<Context> context(Context::Create());
-
- ArtMethod* catch_method = nullptr;
- ArtMethod* throw_method = nullptr;
- uint32_t catch_dex_pc = dex::kDexNoIndex;
- uint32_t throw_dex_pc = dex::kDexNoIndex;
- StackVisitor::WalkStack(
- /**
- * Finds the location where this exception will be caught. We search until we reach the top
- * frame, in which case this exception is considered uncaught.
- */
- [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* method = stack_visitor->GetMethod();
- DCHECK(method != nullptr);
- if (method->IsRuntimeMethod()) {
- // Ignore callee save method.
- DCHECK(method->IsCalleeSaveMethod());
- return true;
- }
-
- uint32_t dex_pc = stack_visitor->GetDexPc();
- if (throw_method == nullptr) {
- // First Java method found. It is either the method that threw the exception,
- // or the Java native method that is reporting an exception thrown by
- // native code.
- this_at_throw.Assign(stack_visitor->GetThisObject());
- throw_method = method;
- throw_dex_pc = dex_pc;
- }
-
- if (dex_pc != dex::kDexNoIndex) {
- StackHandleScope<1> hs(stack_visitor->GetThread());
- uint32_t found_dex_pc;
- Handle<mirror::Class> exception_class(hs.NewHandle(h_exception->GetClass()));
- bool unused_clear_exception;
- found_dex_pc = method->FindCatchBlock(exception_class, dex_pc, &unused_clear_exception);
- if (found_dex_pc != dex::kDexNoIndex) {
- catch_method = method;
- catch_dex_pc = found_dex_pc;
- return false; // End stack walk.
- }
- }
- return true; // Continue stack walk.
- },
- self,
- context.get(),
- art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
-
+ CatchLocationFinder clf(self, h_exception, context.get());
+ clf.WalkStack(/* include_transitions= */ false);
JDWP::EventLocation exception_throw_location;
- SetEventLocation(&exception_throw_location, throw_method, throw_dex_pc);
+ SetEventLocation(&exception_throw_location, clf.GetThrowMethod(), clf.GetThrowDexPc());
JDWP::EventLocation exception_catch_location;
- SetEventLocation(&exception_catch_location, catch_method, catch_dex_pc);
+ SetEventLocation(&exception_catch_location, clf.GetCatchMethod(), clf.GetCatchDexPc());
- gJdwpState->PostException(&exception_throw_location,
- h_exception.Get(),
- &exception_catch_location,
- this_at_throw.Get());
+ gJdwpState->PostException(&exception_throw_location, h_exception.Get(), &exception_catch_location,
+ clf.GetThisAtThrow());
}
void Dbg::PostClassPrepare(mirror::Class* c) {
@@ -3569,6 +3649,56 @@ bool Dbg::IsForcedInterpreterNeededForUpcallImpl(Thread* thread, ArtMethod* m) {
return instrumentation->IsDeoptimized(m);
}
+class NeedsDeoptimizationVisitor : public StackVisitor {
+ public:
+ explicit NeedsDeoptimizationVisitor(Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : StackVisitor(self, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ needs_deoptimization_(false) {}
+
+ bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
+ // The visitor is meant to be used when handling exception from compiled code only.
+ CHECK(!IsShadowFrame()) << "We only expect to visit compiled frame: "
+ << ArtMethod::PrettyMethod(GetMethod());
+ ArtMethod* method = GetMethod();
+ if (method == nullptr) {
+ // We reach an upcall and don't need to deoptimize this part of the stack (ManagedFragment)
+ // so we can stop the visit.
+ DCHECK(!needs_deoptimization_);
+ return false;
+ }
+ if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
+ // We found a compiled frame in the stack but instrumentation is set to interpret
+ // everything: we need to deoptimize.
+ needs_deoptimization_ = true;
+ return false;
+ }
+ if (Runtime::Current()->GetInstrumentation()->IsDeoptimized(method)) {
+ // We found a deoptimized method in the stack.
+ needs_deoptimization_ = true;
+ return false;
+ }
+ ShadowFrame* frame = GetThread()->FindDebuggerShadowFrame(GetFrameId());
+ if (frame != nullptr) {
+ // The debugger allocated a ShadowFrame to update a variable in the stack: we need to
+ // deoptimize the stack to execute (and deallocate) this frame.
+ needs_deoptimization_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool NeedsDeoptimization() const {
+ return needs_deoptimization_;
+ }
+
+ private:
+ // Do we need to deoptimize the stack?
+ bool needs_deoptimization_;
+
+ DISALLOW_COPY_AND_ASSIGN(NeedsDeoptimizationVisitor);
+};
+
// Do we need to deoptimize the stack to handle an exception?
bool Dbg::IsForcedInterpreterNeededForExceptionImpl(Thread* thread) {
const SingleStepControl* const ssc = thread->GetSingleStepControl();
@@ -3578,45 +3708,9 @@ bool Dbg::IsForcedInterpreterNeededForExceptionImpl(Thread* thread) {
}
// Deoptimization is required if at least one method in the stack needs it. However we
// skip frames that will be unwound (thus not executed).
- bool needs_deoptimization = false;
- StackVisitor::WalkStack(
- [&](art::StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
- // The visitor is meant to be used when handling exception from compiled code only.
- CHECK(!visitor->IsShadowFrame()) << "We only expect to visit compiled frame: "
- << ArtMethod::PrettyMethod(visitor->GetMethod());
- ArtMethod* method = visitor->GetMethod();
- if (method == nullptr) {
- // We reach an upcall and don't need to deoptimize this part of the stack (ManagedFragment)
- // so we can stop the visit.
- DCHECK(!needs_deoptimization);
- return false;
- }
- if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
- // We found a compiled frame in the stack but instrumentation is set to interpret
- // everything: we need to deoptimize.
- needs_deoptimization = true;
- return false;
- }
- if (Runtime::Current()->GetInstrumentation()->IsDeoptimized(method)) {
- // We found a deoptimized method in the stack.
- needs_deoptimization = true;
- return false;
- }
- ShadowFrame* frame = visitor->GetThread()->FindDebuggerShadowFrame(visitor->GetFrameId());
- if (frame != nullptr) {
- // The debugger allocated a ShadowFrame to update a variable in the stack: we need to
- // deoptimize the stack to execute (and deallocate) this frame.
- needs_deoptimization = true;
- return false;
- }
- return true;
- },
- thread,
- /* context= */ nullptr,
- art::StackVisitor::StackWalkKind::kIncludeInlinedFrames,
- /* check_suspended */ true,
- /* include_transitions */ true);
- return needs_deoptimization;
+ NeedsDeoptimizationVisitor visitor(thread);
+ visitor.WalkStack(true); // includes upcall.
+ return visitor.NeedsDeoptimization();
}
// Scoped utility class to suspend a thread so that we may do tasks such as walk its stack. Doesn't