diff options
Diffstat (limited to 'runtime/interpreter/interpreter_switch_impl.cc')
-rw-r--r-- | runtime/interpreter/interpreter_switch_impl.cc | 118 |
1 files changed, 91 insertions, 27 deletions
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 27626295c1..c4b03b2563 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -23,16 +23,39 @@ #include "interpreter_common.h" #include "jit/jit.h" #include "jvalue-inl.h" +#include "nth_caller_visitor.h" #include "safe_math.h" #include "shadow_frame-inl.h" +#include "thread.h" namespace art { namespace interpreter { +#define CHECK_FORCE_RETURN() \ + do { \ + if (UNLIKELY(shadow_frame.GetForcePopFrame())) { \ + DCHECK(PrevFrameWillRetry(self, shadow_frame)) \ + << "Pop frame forced without previous frame ready to retry instruction!"; \ + DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); \ + if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) { \ + SendMethodExitEvents(self, \ + instrumentation, \ + shadow_frame, \ + shadow_frame.GetThisObject(accessor.InsSize()), \ + shadow_frame.GetMethod(), \ + inst->GetDexPc(insns), \ + JValue()); \ + } \ + ctx->result = JValue(); /* Handled in caller. */ \ + return; \ + } \ + } while (false) + #define HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instr) \ do { \ DCHECK(self->IsExceptionPending()); \ self->AllowThreadSuspension(); \ + CHECK_FORCE_RETURN(); \ if (!MoveToExceptionHandler(self, shadow_frame, instr)) { \ /* Structured locking is to be enforced for abnormal termination, too. */ \ DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame); \ @@ -43,6 +66,7 @@ namespace interpreter { ctx->result = JValue(); /* Handled in caller. */ \ return; \ } else { \ + CHECK_FORCE_RETURN(); \ int32_t displacement = \ static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc); \ inst = inst->RelativeAt(displacement); \ @@ -51,8 +75,39 @@ namespace interpreter { #define HANDLE_PENDING_EXCEPTION() HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instrumentation) +#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, _next_function) \ + do { \ + if (UNLIKELY(shadow_frame.GetForceRetryInstruction())) { \ + /* Don't need to do anything except clear the flag and exception. We leave the */ \ + /* instruction the same so it will be re-executed on the next go-around. */ \ + DCHECK(inst->IsInvoke()); \ + shadow_frame.SetForceRetryInstruction(false); \ + if (UNLIKELY(_is_exception_pending)) { \ + DCHECK(self->IsExceptionPending()); \ + if (kIsDebugBuild) { \ + LOG(WARNING) << "Suppressing exception for instruction-retry: " \ + << self->GetException()->Dump(); \ + } \ + self->ClearException(); \ + } \ + } else if (UNLIKELY(_is_exception_pending)) { \ + /* Should have succeeded. */ \ + DCHECK(!shadow_frame.GetForceRetryInstruction()); \ + HANDLE_PENDING_EXCEPTION(); \ + } else { \ + inst = inst->_next_function(); \ + } \ + } while (false) + +#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(_is_exception_pending) \ + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_4xx) +#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(_is_exception_pending) \ + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_3xx) + #define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _next_function) \ do { \ + /* Should only be on invoke instructions. */ \ + DCHECK(!shadow_frame.GetForceRetryInstruction()); \ if (UNLIKELY(_is_exception_pending)) { \ HANDLE_PENDING_EXCEPTION(); \ } else { \ @@ -66,17 +121,22 @@ namespace interpreter { } // Code to run before each dex instruction. -#define PREAMBLE_SAVE(save_ref) \ +#define PREAMBLE_SAVE(save_ref) \ { \ - if (UNLIKELY(instrumentation->HasDexPcListeners()) && \ - UNLIKELY(!DoDexPcMoveEvent(self, \ - accessor, \ - shadow_frame, \ - dex_pc, \ - instrumentation, \ - save_ref))) { \ - HANDLE_PENDING_EXCEPTION(); \ - break; \ + /* We need to put this before & after the instrumentation to avoid having to put in a */ \ + /* post-script macro. */ \ + CHECK_FORCE_RETURN(); \ + if (UNLIKELY(instrumentation->HasDexPcListeners())) { \ + if (UNLIKELY(!DoDexPcMoveEvent(self, \ + accessor, \ + shadow_frame, \ + dex_pc, \ + instrumentation, \ + save_ref))) { \ + HANDLE_PENDING_EXCEPTION(); \ + break; \ + } \ + CHECK_FORCE_RETURN(); \ } \ } \ do {} while (false) @@ -180,7 +240,8 @@ NO_INLINE static bool SendMethodExitEvents(Thread* self, const JValue& result) REQUIRES_SHARED(Locks::mutator_lock_) { bool had_event = false; - if (UNLIKELY(instrumentation->HasMethodExitListeners())) { + // We don't send method-exit if it's a pop-frame. We still send frame_popped though. + if (UNLIKELY(instrumentation->HasMethodExitListeners() && !frame.GetForcePopFrame())) { had_event = true; instrumentation->MethodExitEvent(self, thiz.Ptr(), method, dex_pc, result); } @@ -217,6 +278,9 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { uint16_t inst_data; jit::Jit* jit = Runtime::Current()->GetJit(); + DCHECK(!shadow_frame.GetForceRetryInstruction()) + << "Entered interpreter from invoke without retry instruction being handled!"; + do { dex_pc = inst->GetDexPc(insns); shadow_frame.SetDexPC(dex_pc); @@ -1603,84 +1667,84 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { PREAMBLE(); bool success = DoInvoke<kVirtual, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_VIRTUAL_RANGE: { PREAMBLE(); bool success = DoInvoke<kVirtual, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_SUPER: { PREAMBLE(); bool success = DoInvoke<kSuper, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_SUPER_RANGE: { PREAMBLE(); bool success = DoInvoke<kSuper, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_DIRECT: { PREAMBLE(); bool success = DoInvoke<kDirect, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_DIRECT_RANGE: { PREAMBLE(); bool success = DoInvoke<kDirect, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_INTERFACE: { PREAMBLE(); bool success = DoInvoke<kInterface, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_INTERFACE_RANGE: { PREAMBLE(); bool success = DoInvoke<kInterface, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_STATIC: { PREAMBLE(); bool success = DoInvoke<kStatic, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_STATIC_RANGE: { PREAMBLE(); bool success = DoInvoke<kStatic, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_VIRTUAL_QUICK: { PREAMBLE(); bool success = DoInvokeVirtualQuick<false>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { PREAMBLE(); bool success = DoInvokeVirtualQuick<true>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_POLYMORPHIC: { @@ -1688,7 +1752,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokePolymorphic<false /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success); break; } case Instruction::INVOKE_POLYMORPHIC_RANGE: { @@ -1696,7 +1760,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokePolymorphic<true /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success); break; } case Instruction::INVOKE_CUSTOM: { @@ -1704,7 +1768,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokeCustom<false /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::INVOKE_CUSTOM_RANGE: { @@ -1712,7 +1776,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokeCustom<true /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); break; } case Instruction::NEG_INT: |