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_impl-inl.h | |
| 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_impl-inl.h')
| -rw-r--r-- | runtime/interpreter/interpreter_switch_impl-inl.h | 113 |
1 files changed, 45 insertions, 68 deletions
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h index 35708b00c6..222f3775bc 100644 --- a/runtime/interpreter/interpreter_switch_impl-inl.h +++ b/runtime/interpreter/interpreter_switch_impl-inl.h @@ -49,6 +49,11 @@ namespace interpreter { class ActiveTransactionChecker; // For transactional interpreter. class InactiveTransactionChecker; // For non-transactional interpreter. +// We declare the helpers classes for instrumentation handling here but they shall be defined +// only when compiling the transactional and non-transactional interpreter. +class ActiveInstrumentationHandler; // For non-transactional interpreter. +class InactiveInstrumentationHandler; // For transactional interpreter. + // Handles iget-XXX and sget-XXX instructions. // Returns true on success, otherwise throws an exception and returns false. template<FindFieldType find_type, @@ -57,9 +62,13 @@ template<FindFieldType find_type, ALWAYS_INLINE bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, - uint16_t inst_data) REQUIRES_SHARED(Locks::mutator_lock_) { + uint16_t inst_data, + const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_) { + using InstrumentationHandler = typename std::conditional_t< + transaction_active, InactiveInstrumentationHandler, ActiveInstrumentationHandler>; + bool should_report = InstrumentationHandler::HasFieldReadListeners(instrumentation); const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); - bool should_report = Runtime::Current()->GetInstrumentation()->HasFieldReadListeners(); ArtField* field = nullptr; MemberOffset offset(0u); bool is_volatile; @@ -150,9 +159,12 @@ template<FindFieldType find_type, Primitive::Type field_type, bool transaction_a ALWAYS_INLINE bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst, - uint16_t inst_data) + uint16_t inst_data, + const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { - bool should_report = Runtime::Current()->GetInstrumentation()->HasFieldWriteListeners(); + using InstrumentationHandler = typename std::conditional_t< + transaction_active, InactiveInstrumentationHandler, ActiveInstrumentationHandler>; + bool should_report = InstrumentationHandler::HasFieldWriteListeners(instrumentation); bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite); uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); bool resolve_field_type = (shadow_frame.GetVRegReference(vregA) != nullptr); @@ -254,6 +266,8 @@ ALWAYS_INLINE bool DoFieldPut(Thread* self, template<bool transaction_active, Instruction::Format kFormat> class InstructionHandler { public: + using InstrumentationHandler = typename std::conditional_t< + transaction_active, InactiveInstrumentationHandler, ActiveInstrumentationHandler>; using TransactionChecker = typename std::conditional_t< transaction_active, ActiveTransactionChecker, InactiveTransactionChecker>; @@ -268,8 +282,7 @@ class InstructionHandler { DCHECK(abort_exception != nullptr); DCHECK(abort_exception->GetClass()->DescriptorEquals(kTransactionAbortErrorDescriptor)); Self()->ClearException(); - PerformNonStandardReturn( - Self(), shadow_frame_, ctx_->result, Instrumentation(), Accessor().InsSize()); + PerformNonStandardReturn(Self(), shadow_frame_, ctx_->result, Instrumentation()); Self()->SetException(abort_exception.Get()); ExitInterpreterLoop(); return false; @@ -278,10 +291,9 @@ class InstructionHandler { } HANDLER_ATTRIBUTES bool CheckForceReturn() { - if (shadow_frame_.GetForcePopFrame()) { + if (InstrumentationHandler::GetForcePopFrame(shadow_frame_)) { DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); - PerformNonStandardReturn( - Self(), shadow_frame_, ctx_->result, Instrumentation(), Accessor().InsSize()); + PerformNonStandardReturn(Self(), shadow_frame_, ctx_->result, Instrumentation()); ExitInterpreterLoop(); return false; } @@ -348,16 +360,16 @@ class InstructionHandler { if (!CheckForceReturn()) { return false; } - if (UNLIKELY(shadow_frame_.GetNotifyDexPcMoveEvents())) { + if (UNLIKELY(InstrumentationHandler::NeedsDexPcEvents(shadow_frame_))) { uint8_t opcode = inst_->Opcode(inst_data_); bool is_move_result_object = (opcode == Instruction::MOVE_RESULT_OBJECT); JValue* save_ref = is_move_result_object ? &ctx_->result_register : nullptr; - if (UNLIKELY(!DoDexPcMoveEvent(Self(), - Accessor(), - shadow_frame_, - DexPC(), - Instrumentation(), - save_ref))) { + if (UNLIKELY(!InstrumentationHandler::DoDexPcMoveEvent(Self(), + Accessor(), + shadow_frame_, + DexPC(), + Instrumentation(), + save_ref))) { DCHECK(Self()->IsExceptionPending()); // Do not raise exception event if it is caused by other instrumentation event. shadow_frame_.SetSkipNextExceptionEvent(true); @@ -370,53 +382,17 @@ class InstructionHandler { return true; } - // 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; - } - HANDLER_ATTRIBUTES bool HandleReturn(JValue result) { Self()->AllowThreadSuspension(); if (!DoMonitorCheckOnExit(Self(), &shadow_frame_)) { return false; } - if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()) && - !SendMethodExitEvents(Self(), - Instrumentation(), - shadow_frame_, - shadow_frame_.GetMethod(), - result))) { + if (UNLIKELY(InstrumentationHandler::NeedsMethodExitEvent(Instrumentation()) && + !InstrumentationHandler::SendMethodExitEvents(Self(), + Instrumentation(), + shadow_frame_, + shadow_frame_.GetMethod(), + result))) { DCHECK(Self()->IsExceptionPending()); // Do not raise exception event if it is caused by other instrumentation event. shadow_frame_.SetSkipNextExceptionEvent(true); @@ -431,8 +407,9 @@ class InstructionHandler { if (UNLIKELY(Self()->ObserveAsyncException())) { return false; // Pending exception. } - if (UNLIKELY(Instrumentation()->HasBranchListeners())) { - Instrumentation()->Branch(Self(), shadow_frame_.GetMethod(), DexPC(), offset); + if (UNLIKELY(InstrumentationHandler::HasBranchListeners(Instrumentation()))) { + InstrumentationHandler::Branch( + Self(), shadow_frame_.GetMethod(), DexPC(), offset, Instrumentation()); } if (!transaction_active) { // TODO: Do OSR only on back-edges and check if OSR code is ready here. @@ -546,13 +523,13 @@ class InstructionHandler { template<FindFieldType find_type, Primitive::Type field_type> HANDLER_ATTRIBUTES bool HandleGet() { return DoFieldGet<find_type, field_type, transaction_active>( - Self(), shadow_frame_, inst_, inst_data_); + Self(), shadow_frame_, inst_, inst_data_, Instrumentation()); } template<FindFieldType find_type, Primitive::Type field_type> HANDLER_ATTRIBUTES bool HandlePut() { return DoFieldPut<find_type, field_type, transaction_active>( - Self(), shadow_frame_, inst_, inst_data_); + Self(), shadow_frame_, inst_, inst_data_, Instrumentation()); } template<InvokeType type, bool is_range> @@ -686,14 +663,14 @@ class InstructionHandler { } } result.SetL(obj_result); - if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()))) { + if (UNLIKELY(InstrumentationHandler::NeedsMethodExitEvent(Instrumentation()))) { StackHandleScope<1> hs(Self()); MutableHandle<mirror::Object> h_result(hs.NewHandle(obj_result)); - if (!SendMethodExitEvents(Self(), - Instrumentation(), - shadow_frame_, - shadow_frame_.GetMethod(), - h_result)) { + if (!InstrumentationHandler::SendMethodExitEvents(Self(), + Instrumentation(), + shadow_frame_, + shadow_frame_.GetMethod(), + h_result)) { DCHECK(Self()->IsExceptionPending()); // Do not raise exception event if it is caused by other instrumentation event. shadow_frame_.SetSkipNextExceptionEvent(true); |