diff options
author | 2018-03-14 14:44:29 -0700 | |
---|---|---|
committer | 2018-10-04 11:04:49 -0700 | |
commit | 88a2a9d7a14b67e10525d93b0ee57d9dd6bc345a (patch) | |
tree | a19af813a97be817a76072534139a77b16f3ad87 /runtime/thread.cc | |
parent | fc7d33fc052d993eaa205337e6a805022d2cd822 (diff) |
JVMTI PopFrame support
Implement support for the JVMTI can_pop_frames capability. This works
by marking shadow-frames with a bit that forces it to be popped or an
instruction to be retried. When a PopFrame is requested the plugin
will deoptimize the targeted thread and force the interpreter to deal
with the frame pop. If the can_pop_frames capability is enabled the
runtime will be forced to handle all exceptions through the
interpreter. This is required to support PopFrame during some
exception events.
Test: ./test.py --host
Test: ./art/tools/run-libjdwp-tests.sh --mode=host
Bug: 73255278
Bug: 111357976
Change-Id: I62d6b1f4ff387c794ba45093c3d6773aaf642067
Diffstat (limited to 'runtime/thread.cc')
-rw-r--r-- | runtime/thread.cc | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/runtime/thread.cc b/runtime/thread.cc index 4a3d8cbf66..afb2c2850e 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3368,22 +3368,51 @@ void Thread::QuickDeliverException() { HandleWrapperObjPtr<mirror::Throwable> h_exception(hs.NewHandleWrapper(&exception)); instrumentation->ExceptionThrownEvent(this, exception.Ptr()); } - // Does instrumentation need to deoptimize the stack? - // Note: we do this *after* reporting the exception to instrumentation in case it - // now requires deoptimization. It may happen if a debugger is attached and requests - // new events (single-step, breakpoint, ...) when the exception is reported. - if (Dbg::IsForcedInterpreterNeededForException(this)) { + // Does instrumentation need to deoptimize the stack or otherwise go to interpreter for something? + // Note: we do this *after* reporting the exception to instrumentation in case it now requires + // deoptimization. It may happen if a debugger is attached and requests new events (single-step, + // breakpoint, ...) when the exception is reported. + ShadowFrame* cf; + bool force_frame_pop = false; + { + NthCallerVisitor visitor(this, 0, false); + visitor.WalkStack(); + cf = visitor.GetCurrentShadowFrame(); + if (cf == nullptr) { + cf = FindDebuggerShadowFrame(visitor.GetFrameId()); + } + force_frame_pop = cf != nullptr && cf->GetForcePopFrame(); + if (kIsDebugBuild && force_frame_pop) { + NthCallerVisitor penultimate_visitor(this, 1, false); + penultimate_visitor.WalkStack(); + ShadowFrame* penultimate_frame = penultimate_visitor.GetCurrentShadowFrame(); + if (penultimate_frame == nullptr) { + penultimate_frame = FindDebuggerShadowFrame(penultimate_visitor.GetFrameId()); + } + DCHECK(penultimate_frame != nullptr && + penultimate_frame->GetForceRetryInstruction()) + << "Force pop frame without retry instruction found. penultimate frame is null: " + << (penultimate_frame == nullptr ? "true" : "false"); + } + } + if (Dbg::IsForcedInterpreterNeededForException(this) || force_frame_pop) { NthCallerVisitor visitor(this, 0, false); visitor.WalkStack(); if (Runtime::Current()->IsAsyncDeoptimizeable(visitor.caller_pc)) { + VLOG(deopt) << "Deopting " << cf->GetMethod()->PrettyMethod() << " for frame-pop"; // method_type shouldn't matter due to exception handling. const DeoptimizationMethodType method_type = DeoptimizationMethodType::kDefault; // Save the exception into the deoptimization context so it can be restored // before entering the interpreter. + if (force_frame_pop) { + DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); + // Get rid of the exception since we are doing a framepop instead. + ClearException(); + } PushDeoptimizationContext( JValue(), false /* is_reference */, - exception, + (force_frame_pop ? nullptr : exception), false /* from_code */, method_type); artDeoptimize(this); |