Support for deoptimization needed for debugging.

The deoptimization code is untested, and some sanity checks in the
instrumentation are disabled because they need debugging.

Change-Id: I1b60a65a60bddc9b107ad4659da097b55ce901c3
diff --git a/src/oat/runtime/support_deoptimize.cc b/src/oat/runtime/support_deoptimize.cc
new file mode 100644
index 0000000..13fd3ae
--- /dev/null
+++ b/src/oat/runtime/support_deoptimize.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "callee_save_frame.h"
+#include "interpreter/interpreter.h"
+#include "object.h"  // for JValue
+#include "object_utils.h"
+#include "stack.h"
+#include "thread.h"
+#include "verifier/method_verifier.h"
+
+namespace art {
+
+extern "C" uint64_t artDeoptimize(JValue ret_val, Thread* self, AbstractMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  // Return value may hold Object* so avoid suspension.
+  const char* old_cause = self->StartAssertNoThreadSuspension("Deoptimizing stack frame");
+  CHECK(old_cause == NULL);
+  class DeoptimizationVisitor : public StackVisitor {
+   public:
+    DeoptimizationVisitor(const ManagedStack* stack,
+                          const std::deque<InstrumentationStackFrame>* instrumentation_stack,
+                          Context* context)
+        : StackVisitor(stack, instrumentation_stack, context), shadow_frame_(NULL),
+          runtime_frames_(0) { }
+
+    virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+      AbstractMethod* m = GetMethod();
+      if (m->IsRuntimeMethod()) {
+        if (runtime_frames_ == 0) {
+          runtime_frames_++;
+          return true;  // Skip the callee save frame.
+        } else {
+          return false;  // Caller was an upcall.
+        }
+      }
+      MethodHelper mh(m);
+      const DexFile::CodeItem* code_item = mh.GetCodeItem();
+      CHECK(code_item != NULL);
+      uint16_t num_regs =  code_item->registers_size_;
+      shadow_frame_ = ShadowFrame::Create(num_regs, NULL, m, GetDexPc());
+      std::vector<int32_t> kinds =
+          verifier::MethodVerifier::DescribeVRegs(m->GetDexMethodIndex(), &mh.GetDexFile(),
+                                                  mh.GetDexCache(), mh.GetClassLoader(),
+                                                  mh.GetClassDefIndex(), code_item, m,
+                                                  m->GetAccessFlags(), GetDexPc());
+      for(uint16_t reg = 0; reg < num_regs; reg++) {
+        VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
+        switch (kind) {
+          case kUndefined:
+            shadow_frame_->SetVReg(reg, 0xEBADDE09);
+            break;
+          case kConstant:
+            shadow_frame_->SetVReg(reg, kinds.at((reg * 2) + 1));
+            break;
+          default:
+            shadow_frame_->SetVReg(reg, GetVReg(m, reg, kind));
+            break;
+        }
+      }
+      return false;  // Stop now we have built the shadow frame.
+    }
+    ShadowFrame* shadow_frame_;
+    uint32_t runtime_frames_;
+  } visitor(self->GetManagedStack(), self->GetInstrumentationStack(), self->GetLongJumpContext());
+  visitor.WalkStack(false);
+  if (visitor.shadow_frame_ != NULL) {
+    self->SetDeoptimizationShadowFrame(visitor.shadow_frame_, ret_val);
+    return (*sp)->GetFrameSizeInBytes();
+  } else {
+    return 0;  // Caller was an upcall.
+  }
+}
+
+
+extern "C" JValue artEnterInterpreterFromDeoptimize(Thread* self, AbstractMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  JValue return_value;
+  UniquePtr<ShadowFrame> shadow_frame(self->GetAndClearDeoptimizationShadowFrame(&return_value));
+  self->EndAssertNoThreadSuspension(NULL);
+  return interpreter::EnterInterpreterFromDeoptimize(self, *shadow_frame.get(), return_value);
+}
+
+}  // namespace art