summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/interpreter/interpreter.cc2
-rw-r--r--runtime/interpreter/interpreter_common.cc20
-rw-r--r--runtime/interpreter/interpreter_common.h28
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h113
-rw-r--r--runtime/interpreter/interpreter_switch_impl0.cc99
-rw-r--r--runtime/interpreter/interpreter_switch_impl1.cc80
6 files changed, 249 insertions, 93 deletions
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 6097077fe2..fb6f36d5e7 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -309,7 +309,6 @@ static inline JValue Execute(
shadow_frame,
ret,
instrumentation,
- accessor.InsSize(),
/* unlock_monitors= */ false);
return ret;
}
@@ -324,7 +323,6 @@ static inline JValue Execute(
shadow_frame,
ret,
instrumentation,
- accessor.InsSize(),
/* unlock_monitors= */ false);
}
return ret;
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 280136d6a2..4683cd50ee 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1542,6 +1542,26 @@ void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
}
}
+void PerformNonStandardReturn(Thread* self,
+ ShadowFrame& frame,
+ JValue& result,
+ const instrumentation::Instrumentation* instrumentation,
+ bool unlock_monitors) {
+ if (UNLIKELY(self->IsExceptionPending())) {
+ LOG(WARNING) << "Suppressing exception for non-standard method exit: "
+ << self->GetException()->Dump();
+ self->ClearException();
+ }
+ if (unlock_monitors) {
+ UnlockHeldMonitors(self, &frame);
+ DoMonitorCheckOnExit(self, &frame);
+ }
+ result = JValue();
+ if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {
+ SendMethodExitEvents(self, instrumentation, frame, frame.GetMethod(), result);
+ }
+}
+
// Explicit DoCall template function declarations.
#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range) \
template REQUIRES_SHARED(Locks::mutator_lock_) \
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index ba61562d9b..2001e89b9d 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -149,29 +149,11 @@ NeedsMethodExitEvent(const instrumentation::Instrumentation* ins)
COLD_ATTR void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
REQUIRES_SHARED(Locks::mutator_lock_);
-static inline ALWAYS_INLINE void PerformNonStandardReturn(
- Thread* self,
- ShadowFrame& frame,
- JValue& result,
- const instrumentation::Instrumentation* instrumentation,
- uint16_t num_dex_inst,
- bool unlock_monitors = true) REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Object> thiz(frame.GetThisObject(num_dex_inst));
- StackHandleScope<1u> hs(self);
- if (UNLIKELY(self->IsExceptionPending())) {
- LOG(WARNING) << "Suppressing exception for non-standard method exit: "
- << self->GetException()->Dump();
- self->ClearException();
- }
- if (unlock_monitors) {
- UnlockHeldMonitors(self, &frame);
- DoMonitorCheckOnExit(self, &frame);
- }
- result = JValue();
- if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {
- SendMethodExitEvents(self, instrumentation, frame, frame.GetMethod(), result);
- }
-}
+void PerformNonStandardReturn(Thread* self,
+ ShadowFrame& frame,
+ JValue& result,
+ const instrumentation::Instrumentation* instrumentation,
+ bool unlock_monitors = true) REQUIRES_SHARED(Locks::mutator_lock_);
// Handles all invoke-XXX/range instructions except for invoke-polymorphic[/range].
// Returns true on success, otherwise throws an exception and returns false.
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);
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);
diff --git a/runtime/interpreter/interpreter_switch_impl1.cc b/runtime/interpreter/interpreter_switch_impl1.cc
index f0f38514db..2f24ab244c 100644
--- a/runtime/interpreter/interpreter_switch_impl1.cc
+++ b/runtime/interpreter/interpreter_switch_impl1.cc
@@ -115,6 +115,86 @@ void ActiveTransactionChecker::RecordArrayElementsInTransaction(ObjPtr<mirror::O
}
}
+class InactiveInstrumentationHandler {
+ public:
+ ALWAYS_INLINE WARN_UNUSED
+ static bool HasFieldReadListeners(const instrumentation::Instrumentation* instrumentation)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!instrumentation->HasFieldReadListeners());
+ return false;
+ }
+
+ ALWAYS_INLINE WARN_UNUSED
+ static bool HasFieldWriteListeners(const instrumentation::Instrumentation* instrumentation)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!instrumentation->HasFieldWriteListeners());
+ return false;
+ }
+
+ ALWAYS_INLINE WARN_UNUSED
+ static bool HasBranchListeners(const instrumentation::Instrumentation* instrumentation)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!instrumentation->HasBranchListeners());
+ return false;
+ }
+
+ ALWAYS_INLINE WARN_UNUSED
+ static bool NeedsDexPcEvents(ShadowFrame& shadow_frame)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!shadow_frame.GetNotifyDexPcMoveEvents());
+ DCHECK(!Runtime::Current()->GetInstrumentation()->HasDexPcListeners());
+ return false;
+ }
+
+ ALWAYS_INLINE WARN_UNUSED
+ static bool NeedsMethodExitEvent(const instrumentation::Instrumentation* instrumentation)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!interpreter::NeedsMethodExitEvent(instrumentation));
+ return false;
+ }
+
+ ALWAYS_INLINE WARN_UNUSED
+ static bool GetForcePopFrame(ShadowFrame& shadow_frame) {
+ DCHECK(!shadow_frame.GetForcePopFrame());
+ DCHECK(!Runtime::Current()->AreNonStandardExitsEnabled());
+ return false;
+ }
+
+ NO_RETURN
+ static void Branch([[maybe_unused]] Thread* self,
+ [[maybe_unused]] ArtMethod* method,
+ [[maybe_unused]] uint32_t dex_pc,
+ [[maybe_unused]] int32_t dex_pc_offset,
+ [[maybe_unused]] const instrumentation::Instrumentation* instrumentation)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+
+ static bool DoDexPcMoveEvent(
+ [[maybe_unused]] Thread* self,
+ [[maybe_unused]] const CodeItemDataAccessor& accessor,
+ [[maybe_unused]] const ShadowFrame& shadow_frame,
+ [[maybe_unused]] uint32_t dex_pc,
+ [[maybe_unused]] const instrumentation::Instrumentation* instrumentation,
+ [[maybe_unused]] JValue* save_ref)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+
+ template <typename T>
+ static bool SendMethodExitEvents(
+ [[maybe_unused]] Thread* self,
+ [[maybe_unused]] const instrumentation::Instrumentation* instrumentation,
+ [[maybe_unused]] ShadowFrame& frame,
+ [[maybe_unused]] ArtMethod* method,
+ [[maybe_unused]] T& result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+};
+
// Explicit definition of ExecuteSwitchImplCpp.
template
void ExecuteSwitchImplCpp<true>(SwitchImplContext* ctx);