diff options
| author | 2024-05-21 09:08:32 +0000 | |
|---|---|---|
| committer | 2024-05-22 13:07:23 +0000 | |
| commit | a11d8246f846148c83bbcbbe39511c460cc0319a (patch) | |
| tree | c68e33f67340e7872086993c1124cfc87d875be3 /runtime/interpreter/interpreter_switch_impl0.cc | |
| parent | d3f3b2b2790f773c6281730802f52f894d800384 (diff) | |
Refactor instrumentation handling in interpreter.
The transactional interpreter does not need to check for
instrumentation events.
Also change `PerformNonStandartReturn()` which is used only
for unusual code paths (only for instrumentation and aborted
transactions) from `ALWAYS_INLINE` to non-inline and remove
some dead code from it.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing --interp-ac
Change-Id: I2b00c82eac480dd3291f2c7cd68430e606804eaf
Diffstat (limited to 'runtime/interpreter/interpreter_switch_impl0.cc')
| -rw-r--r-- | runtime/interpreter/interpreter_switch_impl0.cc | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/runtime/interpreter/interpreter_switch_impl0.cc b/runtime/interpreter/interpreter_switch_impl0.cc index 517cce8088..378b6895a5 100644 --- a/runtime/interpreter/interpreter_switch_impl0.cc +++ b/runtime/interpreter/interpreter_switch_impl0.cc @@ -58,6 +58,105 @@ class InactiveTransactionChecker { REQUIRES_SHARED(Locks::mutator_lock_) {} }; +class ActiveInstrumentationHandler { + public: + ALWAYS_INLINE WARN_UNUSED + static bool HasFieldReadListeners(const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_) { + return instrumentation->HasFieldReadListeners(); + } + + ALWAYS_INLINE WARN_UNUSED + static bool HasFieldWriteListeners(const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_) { + return instrumentation->HasFieldWriteListeners(); + } + + ALWAYS_INLINE WARN_UNUSED + static bool HasBranchListeners(const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_) { + return instrumentation->HasBranchListeners(); + } + + ALWAYS_INLINE WARN_UNUSED + static bool NeedsDexPcEvents(ShadowFrame& shadow_frame) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK_IMPLIES(shadow_frame.GetNotifyDexPcMoveEvents(), + Runtime::Current()->GetInstrumentation()->HasDexPcListeners()); + return shadow_frame.GetNotifyDexPcMoveEvents(); + } + + ALWAYS_INLINE WARN_UNUSED + static bool NeedsMethodExitEvent(const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_) { + return interpreter::NeedsMethodExitEvent(instrumentation); + } + + ALWAYS_INLINE WARN_UNUSED + static bool GetForcePopFrame(ShadowFrame& shadow_frame) { + DCHECK_IMPLIES(shadow_frame.GetForcePopFrame(), + Runtime::Current()->AreNonStandardExitsEnabled()); + return shadow_frame.GetForcePopFrame(); + } + + ALWAYS_INLINE + static void Branch(Thread* self, + ArtMethod* method, + uint32_t dex_pc, + int32_t dex_pc_offset, + const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_) { + instrumentation->Branch(self, method, dex_pc, dex_pc_offset); + } + + // Unlike most other events the DexPcMovedEvent can be sent when there is a pending exception (if + // the next instruction is MOVE_EXCEPTION). This means it needs to be handled carefully to be able + // to detect exceptions thrown by the DexPcMovedEvent itself. These exceptions could be thrown by + // jvmti-agents while handling breakpoint or single step events. We had to move this into its own + // function because it was making ExecuteSwitchImpl have too large a stack. + NO_INLINE static bool DoDexPcMoveEvent(Thread* self, + const CodeItemDataAccessor& accessor, + const ShadowFrame& shadow_frame, + uint32_t dex_pc, + const instrumentation::Instrumentation* instrumentation, + JValue* save_ref) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(instrumentation->HasDexPcListeners()); + StackHandleScope<2> hs(self); + Handle<mirror::Throwable> thr(hs.NewHandle(self->GetException())); + mirror::Object* null_obj = nullptr; + HandleWrapper<mirror::Object> h( + hs.NewHandleWrapper(LIKELY(save_ref == nullptr) ? &null_obj : save_ref->GetGCRoot())); + self->ClearException(); + instrumentation->DexPcMovedEvent(self, + shadow_frame.GetThisObject(accessor.InsSize()), + shadow_frame.GetMethod(), + dex_pc); + if (UNLIKELY(self->IsExceptionPending())) { + // We got a new exception in the dex-pc-moved event. + // We just let this exception replace the old one. + // TODO It would be good to add the old exception to the + // suppressed exceptions of the new one if possible. + return false; // Pending exception. + } + if (UNLIKELY(!thr.IsNull())) { + self->SetException(thr.Get()); + } + return true; + } + + template <typename T> + ALWAYS_INLINE WARN_UNUSED + static bool SendMethodExitEvents( + Thread* self, + const instrumentation::Instrumentation* instrumentation, + ShadowFrame& frame, + ArtMethod* method, + T& result) REQUIRES_SHARED(Locks::mutator_lock_) { + return interpreter::SendMethodExitEvents(self, instrumentation, frame, method, result); + } +}; + // Explicit definition of ExecuteSwitchImplCpp. template HOT_ATTR void ExecuteSwitchImplCpp<false>(SwitchImplContext* ctx); |