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_);