diff options
author | 2019-03-20 15:52:13 -0700 | |
---|---|---|
committer | 2019-06-10 18:33:25 +0000 | |
commit | b7c640d364d32b79cb52d04750b063667a9a0c86 (patch) | |
tree | 9caafc96879f83f8e5dd3cd45b9005be6e2b7deb /runtime/interpreter/interpreter_switch_impl-inl.h | |
parent | 3ffb5b1576f8af0c361284ebd8d2d54c70ede3ff (diff) |
JVMTI Force early return
Add support for can_force_early_return jvmti capability. This allows
one to force java frames to exit early. Exited frames have all of
their normal locks released.
We implement this by modifying the existing method exit events to
allow one to modify the exit value during the callback. This is used
to implement ForceEarlyReturn by adding internal-only events that will
change the return value of methods once they return (using
kForcePopFrame) avoiding the need to modify the actual interpreter
very deeply. This also makes it simple to continue to use the standard
deoptimization functions to force the actual return.
In order to simplify book-keeping the internal event is refcounted,
not associated with any specific jvmtiEnv, and only settable on
specific threads. The internal event is added by the ForceEarlyReturn
function and then removed by the MethodExit event when we update the
return value.
Bug: 130028055
Test: ./test.py --host
Change-Id: Ifa44605b4e8032605f503a654ddf4bd2fc6b60bf
Diffstat (limited to 'runtime/interpreter/interpreter_switch_impl-inl.h')
-rw-r--r-- | runtime/interpreter/interpreter_switch_impl-inl.h | 98 |
1 files changed, 14 insertions, 84 deletions
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h index a487cd6630..085c475783 100644 --- a/runtime/interpreter/interpreter_switch_impl-inl.h +++ b/runtime/interpreter/interpreter_switch_impl-inl.h @@ -33,6 +33,7 @@ #include "jvalue-inl.h" #include "mirror/string-alloc-inl.h" #include "mirror/throwable.h" +#include "monitor.h" #include "nth_caller_visitor.h" #include "safe_math.h" #include "shadow_frame-inl.h" @@ -54,56 +55,14 @@ namespace interpreter { template<bool do_access_check, bool transaction_active, Instruction::Format kFormat> class InstructionHandler { public: - template <bool kMonitorCounting> - static NO_INLINE void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame) - REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(shadow_frame->GetForcePopFrame()); - // Unlock all monitors. - if (kMonitorCounting && shadow_frame->GetMethod()->MustCountLocks()) { - // Get the monitors from the shadow-frame monitor-count data. - shadow_frame->GetLockCountData().VisitMonitors( - [&](mirror::Object** obj) REQUIRES_SHARED(Locks::mutator_lock_) { - // Since we don't use the 'obj' pointer after the DoMonitorExit everything should be fine - // WRT suspension. - DoMonitorExit<do_assignability_check>(self, shadow_frame, *obj); - }); - } else { - std::vector<verifier::MethodVerifier::DexLockInfo> locks; - verifier::MethodVerifier::FindLocksAtDexPc(shadow_frame->GetMethod(), - shadow_frame->GetDexPC(), - &locks, - Runtime::Current()->GetTargetSdkVersion()); - for (const auto& reg : locks) { - if (UNLIKELY(reg.dex_registers.empty())) { - LOG(ERROR) << "Unable to determine reference locked by " - << shadow_frame->GetMethod()->PrettyMethod() << " at pc " - << shadow_frame->GetDexPC(); - } else { - DoMonitorExit<do_assignability_check>( - self, shadow_frame, shadow_frame->GetVRegReference(*reg.dex_registers.begin())); - } - } - } - } - ALWAYS_INLINE WARN_UNUSED bool CheckForceReturn() REQUIRES_SHARED(Locks::mutator_lock_) { - if (UNLIKELY(shadow_frame.GetForcePopFrame())) { - DCHECK(PrevFrameWillRetry(self, shadow_frame)) - << "Pop frame forced without previous frame ready to retry instruction!"; - DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); - UnlockHeldMonitors<do_assignability_check>(self, &shadow_frame); - DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame); - 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. */ + if (PerformNonStandardReturn<kMonitorState>(self, + shadow_frame, + ctx->result, + instrumentation, + Accessor().InsSize(), + inst->GetDexPc(Insns()))) { exit_interpreter_loop = true; return false; } @@ -339,39 +298,6 @@ class InstructionHandler { } } - static bool NeedsMethodExitEvent(const instrumentation::Instrumentation* ins) - REQUIRES_SHARED(Locks::mutator_lock_) { - return ins->HasMethodExitListeners() || ins->HasWatchedFramePopListeners(); - } - - // Sends the normal method exit event. - // Returns true if the events succeeded and false if there is a pending exception. - NO_INLINE static bool SendMethodExitEvents( - Thread* self, - const instrumentation::Instrumentation* instrumentation, - const ShadowFrame& frame, - ObjPtr<mirror::Object> thiz, - ArtMethod* method, - uint32_t dex_pc, - const JValue& result) - REQUIRES_SHARED(Locks::mutator_lock_) { - bool had_event = false; - // 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, method, dex_pc, result); - } - if (UNLIKELY(frame.NeedsNotifyPop() && instrumentation->HasWatchedFramePopListeners())) { - had_event = true; - instrumentation->WatchedFramePopped(self, frame); - } - if (UNLIKELY(had_event)) { - return !self->IsExceptionPending(); - } else { - return true; - } - } - #define BRANCH_INSTRUMENTATION(offset) \ if (!BranchInstrumentation(offset)) { \ return false; \ @@ -700,6 +626,8 @@ class InstructionHandler { HANDLE_PENDING_EXCEPTION(); } } + StackHandleScope<1> hs(self); + MutableHandle<mirror::Object> h_result(hs.NewHandle(obj_result)); result.SetL(obj_result); if (UNLIKELY(NeedsMethodExitEvent(instrumentation) && !SendMethodExitEvents(self, @@ -708,13 +636,13 @@ class InstructionHandler { shadow_frame.GetThisObject(Accessor().InsSize()), shadow_frame.GetMethod(), inst->GetDexPc(Insns()), - result))) { + h_result))) { if (!HandlePendingExceptionWithInstrumentation(nullptr)) { return false; } } - // Re-load since it might have moved during the MethodExitEvent. - result.SetL(GetVRegReference(ref_idx)); + // Re-load since it might have moved or been replaced during the MethodExitEvent. + result.SetL(h_result.Get()); if (ctx->interpret_one_instruction) { /* Signal mterp to return to caller */ shadow_frame.SetDexPC(dex::kDexNoIndex); @@ -2198,6 +2126,8 @@ class InstructionHandler { private: static constexpr bool do_assignability_check = do_access_check; + static constexpr MonitorState kMonitorState = + do_assignability_check ? MonitorState::kCountingMonitors : MonitorState::kNormalMonitors; const CodeItemDataAccessor& Accessor() { return ctx->accessor; } const uint16_t* Insns() { return ctx->accessor.Insns(); } |