Changes to LLVM to support deoptimization.

Added a magic exception value (-1) and a handler to transition
to the interpreter. This is currently untested.

Change-Id: I2f53135e7505c54355ecf7c579897f68bbdcbda3
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index cc3c3f9..f5d6e8c 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -780,7 +780,19 @@
     EmitUpdateDexPC(dex_pc);
   }
   irb_.Runtime().EmitTestSuspend();
-  irb_.CreateBr(basic_block_cont);
+
+  llvm::BasicBlock* basic_block_exception = CreateBasicBlockWithDexPC(dex_pc, "exception");
+  llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
+  irb_.CreateCondBr(exception_pending, basic_block_exception, basic_block_cont, kUnlikely);
+
+  irb_.SetInsertPoint(basic_block_exception);
+  llvm::Type* ret_type = call_inst.getParent()->getParent()->getReturnType();
+  if (ret_type->isVoidTy()) {
+    irb_.CreateRetVoid();
+  } else {
+    // The return value is ignored when there's an exception.
+    irb_.CreateRet(llvm::UndefValue::get(ret_type));
+  }
 
   irb_.SetInsertPoint(basic_block_cont);
   return;
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index f32bcde..d0fe4c3 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -38,6 +38,7 @@
 #include "thread.h"
 #include "thread_list.h"
 #include "utils_llvm.h"
+#include "verifier/dex_gc_map.h"
 #include "verifier/method_verifier.h"
 #include "well_known_classes.h"
 
@@ -49,6 +50,57 @@
 
 namespace art {
 
+class ShadowFrameCopyVisitor : public StackVisitor {
+ public:
+  explicit ShadowFrameCopyVisitor(Thread* self) : StackVisitor(self, NULL), prev_frame_(NULL),
+      top_frame_(NULL) {}
+
+  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (IsShadowFrame()) {
+      ShadowFrame* cur_frame = GetCurrentShadowFrame();
+      size_t num_regs = cur_frame->NumberOfVRegs();
+      mirror::AbstractMethod* method = cur_frame->GetMethod();
+      uint32_t dex_pc = cur_frame->GetDexPC();
+      ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
+
+      const uint8_t* gc_map = method->GetNativeGcMap();
+      uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
+                                                     (gc_map[1] << 16) |
+                                                     (gc_map[2] << 8) |
+                                                     (gc_map[3] << 0));
+      verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
+      const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
+      for (size_t reg = 0; reg < num_regs; ++reg) {
+        if (TestBitmap(reg, reg_bitmap)) {
+          new_frame->SetVRegReference(reg, cur_frame->GetVRegReference(reg));
+        } else {
+          new_frame->SetVReg(reg, cur_frame->GetVReg(reg));
+        }
+      }
+
+      if (prev_frame_ != NULL) {
+        prev_frame_->SetLink(new_frame);
+      } else {
+        top_frame_ = new_frame;
+      }
+      prev_frame_ = new_frame;
+    }
+    return true;
+  }
+
+  ShadowFrame* GetShadowFrameCopy() {
+    return top_frame_;
+  }
+
+ private:
+  static bool TestBitmap(int reg, const uint8_t* reg_vector) {
+    return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
+  }
+
+  ShadowFrame* prev_frame_;
+  ShadowFrame* top_frame_;
+};
+
 //----------------------------------------------------------------------------
 // Thread
 //----------------------------------------------------------------------------
@@ -85,6 +137,13 @@
 void art_test_suspend_from_code(Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CheckSuspend(thread);
+  if (thread->ReadFlag(kEnterInterpreter)) {
+    // Save out the shadow frame to the heap
+    ShadowFrameCopyVisitor visitor(thread);
+    visitor.WalkStack(true);
+    thread->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy(), JValue());
+    thread->SetException(reinterpret_cast<mirror::Throwable*>(-1));
+  }
 }
 
 ShadowFrame* art_push_shadow_frame_from_code(Thread* thread, ShadowFrame* new_shadow_frame,
@@ -155,7 +214,12 @@
 
 int32_t art_find_catch_block_from_code(mirror::AbstractMethod* current_method, uint32_t ti_offset)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Class* exception_type = Thread::Current()->GetException()->GetClass();
+  mirror::Throwable* exception = Thread::Current()->GetException();
+  // Check for magic deoptimization exception.
+  if (reinterpret_cast<int32_t>(exception) == -1) {
+    return -1;
+  }
+  mirror::Class* exception_type = exception->GetClass();
   MethodHelper mh(current_method);
   const DexFile::CodeItem* code_item = mh.GetCodeItem();
   DCHECK_LT(ti_offset, code_item->tries_size_);
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 65729c9..bd63c30 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -1880,6 +1880,21 @@
   return Execute(self, mh, code_item, shadow_frame, ret_val);
 }
 
+void EnterInterpreterFromLLVM(Thread* self, ShadowFrame* shadow_frame, JValue* ret_val)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  JValue value;
+  MethodHelper mh(shadow_frame->GetMethod());
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  while (shadow_frame != NULL) {
+    value = Execute(self, mh, code_item, *shadow_frame, value);
+    ShadowFrame* old_frame = shadow_frame;
+    shadow_frame = shadow_frame->GetLink();
+    mh.ChangeMethod(shadow_frame->GetMethod());
+    delete old_frame;
+  }
+  ret_val->SetJ(value.GetJ());
+}
+
 JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                                 ShadowFrame& shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index eee13dc..12da736 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -41,6 +41,9 @@
                                              JValue ret_val)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+void EnterInterpreterFromLLVM(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 extern JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh,
                                        const DexFile::CodeItem* code_item,
                                        ShadowFrame& shadow_frame)
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 4641941..84b8809 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -304,6 +304,16 @@
                                   PrettyMethod(this).c_str(), GetCode(), stub);
       }
       (*stub)(this, receiver, self, args, result);
+      if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException()) == -1)) {
+        // Unusual case where we were running LLVM generated code and an
+        // exception was thrown to force the activations to be removed from the
+        // stack. Continue execution in the interpreter.
+        JValue value;
+        self->ClearException();
+        ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(&value);
+        self->SetTopOfShadowStack(shadow_frame);
+        interpreter::EnterInterpreterFromLLVM(self, shadow_frame, result);
+      }
       if (kLogInvocationStartAndReturn) {
         LOG(INFO) << StringPrintf("Returned '%s' code=%p stub=%p",
                                   PrettyMethod(this).c_str(), GetCode(), stub);
diff --git a/src/stack.h b/src/stack.h
index c3d20f5..18a2101 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -315,6 +315,10 @@
     return top_shadow_frame_;
   }
 
+  void SetTopShadowFrame(ShadowFrame* top) {
+    top_shadow_frame_ = top;
+  }
+
   static size_t TopShadowFrameOffset() {
     return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_);
   }
diff --git a/src/thread.h b/src/thread.h
index c63fddf..5e424c1 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -325,6 +325,10 @@
     managed_stack_.SetTopQuickFramePc(pc);
   }
 
+  void SetTopOfShadowStack(ShadowFrame* top) {
+    managed_stack_.SetTopShadowFrame(top);
+  }
+
   bool HasManagedStack() const {
     return managed_stack_.GetTopQuickFrame() != NULL || managed_stack_.GetTopShadowFrame() != NULL;
   }