diff options
| -rw-r--r-- | src/compiler_llvm/gbc_expander.cc | 14 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_llvm.cc | 66 | ||||
| -rw-r--r-- | src/interpreter/interpreter.cc | 15 | ||||
| -rw-r--r-- | src/interpreter/interpreter.h | 3 | ||||
| -rw-r--r-- | src/mirror/abstract_method.cc | 10 | ||||
| -rw-r--r-- | src/stack.h | 4 | ||||
| -rw-r--r-- | src/thread.h | 4 |
7 files changed, 114 insertions, 2 deletions
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc index cc3c3f93f4..f5d6e8c186 100644 --- a/src/compiler_llvm/gbc_expander.cc +++ b/src/compiler_llvm/gbc_expander.cc @@ -780,7 +780,19 @@ void GBCExpanderPass::Expand_TestSuspend(llvm::CallInst& call_inst) { 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 f32bcde94f..d0fe4c307b 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_unlock_object_from_code(mirror::Object* obj, Thread* thread) 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 @@ void* art_get_and_clear_exception(Thread* self) 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 65729c9394..bd63c30fb4 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -1880,6 +1880,21 @@ JValue EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame& shadow_frame, J 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 eee13dc1b3..12da736253 100644 --- a/src/interpreter/interpreter.h +++ b/src/interpreter/interpreter.h @@ -41,6 +41,9 @@ extern JValue EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame& shadow_f 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 4641941ef9..84b8809009 100644 --- a/src/mirror/abstract_method.cc +++ b/src/mirror/abstract_method.cc @@ -304,6 +304,16 @@ void AbstractMethod::Invoke(Thread* self, Object* receiver, JValue* args, JValue 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 c3d20f5ef6..18a2101508 100644 --- a/src/stack.h +++ b/src/stack.h @@ -315,6 +315,10 @@ class PACKED(4) ManagedStack { 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 c63fddf3d1..5e424c1cd5 100644 --- a/src/thread.h +++ b/src/thread.h @@ -325,6 +325,10 @@ class PACKED(4) Thread { managed_stack_.SetTopQuickFramePc(pc); } + void SetTopOfShadowStack(ShadowFrame* top) { + managed_stack_.SetTopShadowFrame(top); + } + bool HasManagedStack() const { return managed_stack_.GetTopQuickFrame() != NULL || managed_stack_.GetTopShadowFrame() != NULL; } |