From 99170c636dfae4908b102347cfe9f92bad1881cc Mon Sep 17 00:00:00 2001 From: Mingyao Yang Date: Mon, 6 Jul 2015 11:10:37 -0700 Subject: Deoptimization support in optimizing compiler for setting local values Due to compiler optimizations, we may not always be able to update the value of a local variable in a compiled frame (like a variable seen as constant by the compiler). To avoid that situation, we simply deoptimize compiled frames updated by the debugger so they are executed by the interpreter with the updated value. When the debugger attempts to set a local variable (actually a DEX register or a pair of registers) in a compiled frame, we allocate a ShadowFrame associated to that frame (using its frame id) and set the new value in that ShadowFrame. When we know we are about to continue the execution of the compiled frame, we deoptimize the stack using the preallocated ShadowFrame (instead of creating a new one). We initialize it with the current value of all DEX registers except the ones that have been set by the debugger. Therefore, the ShadowFrame represent the runtime context modified by the debugger. Bumps oat version to force recompilation. Bug: 19944235 Change-Id: I0ebe6241264f7a3be0f14ee4516c1f7436e04da6 --- runtime/quick_exception_handler.cc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'runtime/quick_exception_handler.cc') diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index d797d2ad60..5c13e13f90 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -100,6 +100,15 @@ class CatchBlockStackVisitor FINAL : public StackVisitor { method->ToNativeQuickPc(found_dex_pc, /* is_catch_handler */ true)); exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); return false; // End stack walk. + } else if (UNLIKELY(GetThread()->HasDebuggerShadowFrames())) { + // We are going to unwind this frame. Did we prepare a shadow frame for debugging? + size_t frame_id = GetFrameId(); + ShadowFrame* frame = GetThread()->FindDebuggerShadowFrame(frame_id); + if (frame != nullptr) { + // We will not execute this shadow frame so we can safely deallocate it. + GetThread()->RemoveDebuggerShadowFrameMapping(frame_id); + ShadowFrame::DeleteDeoptimizedFrame(frame); + } } } return true; // Continue stack walk. @@ -310,7 +319,17 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { true, true); bool verifier_success = verifier.Verify(); CHECK(verifier_success) << PrettyMethod(m); - ShadowFrame* new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, m, dex_pc); + // Check if a shadow frame already exists for debugger's set-local-value purpose. + const size_t frame_id = GetFrameId(); + ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id); + const bool* updated_vregs; + if (new_frame == nullptr) { + new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, m, dex_pc); + updated_vregs = nullptr; + } else { + updated_vregs = GetThread()->GetUpdatedVRegFlags(frame_id); + DCHECK(updated_vregs != nullptr); + } { ScopedStackedShadowFramePusher pusher(GetThread(), new_frame, StackedShadowFrameType::kShadowFrameUnderConstruction); @@ -322,6 +341,10 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { static constexpr uint32_t kDeadValue = 0xEBADDE09; static constexpr uint64_t kLongDeadValue = 0xEBADDE09EBADDE09; for (uint16_t reg = 0; reg < num_regs; ++reg) { + if (updated_vregs != nullptr && updated_vregs[reg]) { + // Keep the value set by debugger. + continue; + } VRegKind kind = GetVRegKind(reg, kinds); switch (kind) { case kUndefined: @@ -413,6 +436,12 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { } } } + if (updated_vregs != nullptr) { + // Calling Thread::RemoveDebuggerShadowFrameMapping will also delete the updated_vregs + // array so this must come after we processed the frame. + GetThread()->RemoveDebuggerShadowFrameMapping(frame_id); + DCHECK(GetThread()->FindDebuggerShadowFrame(frame_id) == nullptr); + } if (prev_shadow_frame_ != nullptr) { prev_shadow_frame_->SetLink(new_frame); } else { -- cgit v1.2.3-59-g8ed1b