summaryrefslogtreecommitdiff
path: root/runtime/quick_exception_handler.cc
diff options
context:
space:
mode:
authorMingyao Yang <mingyao@google.com>2015-07-06 11:10:37 -0700
committerSebastien Hertz <shertz@google.com>2015-09-17 17:07:22 +0200
commit99170c636dfae4908b102347cfe9f92bad1881cc (patch)
tree1ecff5dd69ea20b09e622cb88e7835a55dfa4be8 /runtime/quick_exception_handler.cc
parent5836f8465ddd0a7f5cbeec9c30d739bd0619867f (diff)
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
Diffstat (limited to 'runtime/quick_exception_handler.cc')
-rw-r--r--runtime/quick_exception_handler.cc31
1 files changed, 30 insertions, 1 deletions
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 {