summaryrefslogtreecommitdiff
path: root/runtime/interpreter/interpreter_switch_impl0.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2024-05-21 09:08:32 +0000
committer VladimĂ­r Marko <vmarko@google.com> 2024-05-22 13:07:23 +0000
commita11d8246f846148c83bbcbbe39511c460cc0319a (patch)
treec68e33f67340e7872086993c1124cfc87d875be3 /runtime/interpreter/interpreter_switch_impl0.cc
parentd3f3b2b2790f773c6281730802f52f894d800384 (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.cc99
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);