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
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index d797d2a..5c13e13 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -100,6 +100,15 @@
             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 @@
                                       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 @@
       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 @@
         }
       }
     }
+    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 {