summaryrefslogtreecommitdiff
path: root/runtime/instrumentation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/instrumentation.cc')
-rw-r--r--runtime/instrumentation.cc355
1 files changed, 184 insertions, 171 deletions
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index deada4c5dc..e937397d80 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -36,6 +36,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "nth_caller_visitor.h"
+#include "oat_quick_method_header.h"
#include "thread.h"
#include "thread_list.h"
@@ -96,16 +97,6 @@ void Instrumentation::InstallStubsForClass(mirror::Class* klass) {
static void UpdateEntrypoints(ArtMethod* method, const void* quick_code)
SHARED_REQUIRES(Locks::mutator_lock_) {
- Runtime* const runtime = Runtime::Current();
- jit::Jit* jit = runtime->GetJit();
- if (jit != nullptr) {
- const void* old_code_ptr = method->GetEntryPointFromQuickCompiledCode();
- jit::JitCodeCache* code_cache = jit->GetCodeCache();
- if (code_cache->ContainsCodePtr(old_code_ptr)) {
- // Save the old compiled code since we need it to implement ClassLinker::GetQuickOatCodeFor.
- code_cache->SaveCompiledCode(method, old_code_ptr);
- }
- }
method->SetEntryPointFromQuickCompiledCode(quick_code);
}
@@ -251,7 +242,9 @@ static void InstrumentationInstallStack(Thread* thread, void* arg)
instrumentation_stack_->insert(it, instrumentation_frame);
SetReturnPc(instrumentation_exit_pc_);
}
- dex_pcs_.push_back(m->ToDexPc(last_return_pc_));
+ dex_pcs_.push_back((GetCurrentOatQuickMethodHeader() == nullptr)
+ ? DexFile::kDexNoIndex
+ : GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_));
last_return_pc_ = return_pc;
++instrumentation_stack_depth_;
return true; // Continue.
@@ -394,146 +387,151 @@ static bool HasEvent(Instrumentation::InstrumentationEvent expected, uint32_t ev
return (events & expected) != 0;
}
-void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
+static void PotentiallyAddListenerTo(Instrumentation::InstrumentationEvent event,
+ uint32_t events,
+ std::list<InstrumentationListener*>& list,
+ InstrumentationListener* listener,
+ bool* has_listener)
+ REQUIRES(Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::classlinker_classes_lock_) {
Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
- if (HasEvent(kMethodEntered, events)) {
- method_entry_listeners_.push_back(listener);
- have_method_entry_listeners_ = true;
- }
- if (HasEvent(kMethodExited, events)) {
- method_exit_listeners_.push_back(listener);
- have_method_exit_listeners_ = true;
- }
- if (HasEvent(kMethodUnwind, events)) {
- method_unwind_listeners_.push_back(listener);
- have_method_unwind_listeners_ = true;
- }
- if (HasEvent(kBackwardBranch, events)) {
- backward_branch_listeners_.push_back(listener);
- have_backward_branch_listeners_ = true;
- }
- if (HasEvent(kInvokeVirtualOrInterface, events)) {
- invoke_virtual_or_interface_listeners_.push_back(listener);
- have_invoke_virtual_or_interface_listeners_ = true;
- }
- if (HasEvent(kDexPcMoved, events)) {
- std::list<InstrumentationListener*>* modified;
- if (have_dex_pc_listeners_) {
- modified = new std::list<InstrumentationListener*>(*dex_pc_listeners_.get());
- } else {
- modified = new std::list<InstrumentationListener*>();
- }
- modified->push_back(listener);
- dex_pc_listeners_.reset(modified);
- have_dex_pc_listeners_ = true;
- }
- if (HasEvent(kFieldRead, events)) {
- std::list<InstrumentationListener*>* modified;
- if (have_field_read_listeners_) {
- modified = new std::list<InstrumentationListener*>(*field_read_listeners_.get());
- } else {
- modified = new std::list<InstrumentationListener*>();
- }
- modified->push_back(listener);
- field_read_listeners_.reset(modified);
- have_field_read_listeners_ = true;
- }
- if (HasEvent(kFieldWritten, events)) {
- std::list<InstrumentationListener*>* modified;
- if (have_field_write_listeners_) {
- modified = new std::list<InstrumentationListener*>(*field_write_listeners_.get());
- } else {
- modified = new std::list<InstrumentationListener*>();
- }
- modified->push_back(listener);
- field_write_listeners_.reset(modified);
- have_field_write_listeners_ = true;
+ if (!HasEvent(event, events)) {
+ return;
}
- if (HasEvent(kExceptionCaught, events)) {
- std::list<InstrumentationListener*>* modified;
- if (have_exception_caught_listeners_) {
- modified = new std::list<InstrumentationListener*>(*exception_caught_listeners_.get());
- } else {
- modified = new std::list<InstrumentationListener*>();
- }
- modified->push_back(listener);
- exception_caught_listeners_.reset(modified);
- have_exception_caught_listeners_ = true;
+ // If there is a free slot in the list, we insert the listener in that slot.
+ // Otherwise we add it to the end of the list.
+ auto it = std::find(list.begin(), list.end(), nullptr);
+ if (it != list.end()) {
+ *it = listener;
+ } else {
+ list.push_back(listener);
}
- UpdateInterpreterHandlerTable();
+ *has_listener = true;
}
-void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
+void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
+ PotentiallyAddListenerTo(kMethodEntered,
+ events,
+ method_entry_listeners_,
+ listener,
+ &have_method_entry_listeners_);
+ PotentiallyAddListenerTo(kMethodExited,
+ events,
+ method_exit_listeners_,
+ listener,
+ &have_method_exit_listeners_);
+ PotentiallyAddListenerTo(kMethodUnwind,
+ events,
+ method_unwind_listeners_,
+ listener,
+ &have_method_unwind_listeners_);
+ PotentiallyAddListenerTo(kBackwardBranch,
+ events,
+ backward_branch_listeners_,
+ listener,
+ &have_backward_branch_listeners_);
+ PotentiallyAddListenerTo(kInvokeVirtualOrInterface,
+ events,
+ invoke_virtual_or_interface_listeners_,
+ listener,
+ &have_invoke_virtual_or_interface_listeners_);
+ PotentiallyAddListenerTo(kDexPcMoved,
+ events,
+ dex_pc_listeners_,
+ listener,
+ &have_dex_pc_listeners_);
+ PotentiallyAddListenerTo(kFieldRead,
+ events,
+ field_read_listeners_,
+ listener,
+ &have_field_read_listeners_);
+ PotentiallyAddListenerTo(kFieldWritten,
+ events,
+ field_write_listeners_,
+ listener,
+ &have_field_write_listeners_);
+ PotentiallyAddListenerTo(kExceptionCaught,
+ events,
+ exception_caught_listeners_,
+ listener,
+ &have_exception_caught_listeners_);
+ UpdateInterpreterHandlerTable();
+}
- if (HasEvent(kMethodEntered, events) && have_method_entry_listeners_) {
- method_entry_listeners_.remove(listener);
- have_method_entry_listeners_ = !method_entry_listeners_.empty();
- }
- if (HasEvent(kMethodExited, events) && have_method_exit_listeners_) {
- method_exit_listeners_.remove(listener);
- have_method_exit_listeners_ = !method_exit_listeners_.empty();
- }
- if (HasEvent(kMethodUnwind, events) && have_method_unwind_listeners_) {
- method_unwind_listeners_.remove(listener);
- have_method_unwind_listeners_ = !method_unwind_listeners_.empty();
- }
- if (HasEvent(kBackwardBranch, events) && have_backward_branch_listeners_) {
- backward_branch_listeners_.remove(listener);
- have_backward_branch_listeners_ = !backward_branch_listeners_.empty();
- }
- if (HasEvent(kInvokeVirtualOrInterface, events) && have_invoke_virtual_or_interface_listeners_) {
- invoke_virtual_or_interface_listeners_.remove(listener);
- have_invoke_virtual_or_interface_listeners_ = !invoke_virtual_or_interface_listeners_.empty();
- }
- if (HasEvent(kDexPcMoved, events) && have_dex_pc_listeners_) {
- std::list<InstrumentationListener*>* modified =
- new std::list<InstrumentationListener*>(*dex_pc_listeners_.get());
- modified->remove(listener);
- have_dex_pc_listeners_ = !modified->empty();
- if (have_dex_pc_listeners_) {
- dex_pc_listeners_.reset(modified);
- } else {
- dex_pc_listeners_.reset();
- delete modified;
- }
+static void PotentiallyRemoveListenerFrom(Instrumentation::InstrumentationEvent event,
+ uint32_t events,
+ std::list<InstrumentationListener*>& list,
+ InstrumentationListener* listener,
+ bool* has_listener)
+ REQUIRES(Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::classlinker_classes_lock_) {
+ Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
+ if (!HasEvent(event, events)) {
+ return;
}
- if (HasEvent(kFieldRead, events) && have_field_read_listeners_) {
- std::list<InstrumentationListener*>* modified =
- new std::list<InstrumentationListener*>(*field_read_listeners_.get());
- modified->remove(listener);
- have_field_read_listeners_ = !modified->empty();
- if (have_field_read_listeners_) {
- field_read_listeners_.reset(modified);
- } else {
- field_read_listeners_.reset();
- delete modified;
- }
+ auto it = std::find(list.begin(), list.end(), listener);
+ if (it != list.end()) {
+ // Just update the entry, do not remove from the list. Removing entries in the list
+ // is unsafe when mutators are iterating over it.
+ *it = nullptr;
}
- if (HasEvent(kFieldWritten, events) && have_field_write_listeners_) {
- std::list<InstrumentationListener*>* modified =
- new std::list<InstrumentationListener*>(*field_write_listeners_.get());
- modified->remove(listener);
- have_field_write_listeners_ = !modified->empty();
- if (have_field_write_listeners_) {
- field_write_listeners_.reset(modified);
- } else {
- field_write_listeners_.reset();
- delete modified;
- }
- }
- if (HasEvent(kExceptionCaught, events) && have_exception_caught_listeners_) {
- std::list<InstrumentationListener*>* modified =
- new std::list<InstrumentationListener*>(*exception_caught_listeners_.get());
- modified->remove(listener);
- have_exception_caught_listeners_ = !modified->empty();
- if (have_exception_caught_listeners_) {
- exception_caught_listeners_.reset(modified);
- } else {
- exception_caught_listeners_.reset();
- delete modified;
+
+ // Check if the list contains any non-null listener, and update 'has_listener'.
+ for (InstrumentationListener* l : list) {
+ if (l != nullptr) {
+ *has_listener = true;
+ return;
}
}
+ *has_listener = false;
+}
+
+void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
+ Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
+ PotentiallyRemoveListenerFrom(kMethodEntered,
+ events,
+ method_entry_listeners_,
+ listener,
+ &have_method_entry_listeners_);
+ PotentiallyRemoveListenerFrom(kMethodExited,
+ events,
+ method_exit_listeners_,
+ listener,
+ &have_method_exit_listeners_);
+ PotentiallyRemoveListenerFrom(kMethodUnwind,
+ events,
+ method_unwind_listeners_,
+ listener,
+ &have_method_unwind_listeners_);
+ PotentiallyRemoveListenerFrom(kBackwardBranch,
+ events,
+ backward_branch_listeners_,
+ listener,
+ &have_backward_branch_listeners_);
+ PotentiallyRemoveListenerFrom(kInvokeVirtualOrInterface,
+ events,
+ invoke_virtual_or_interface_listeners_,
+ listener,
+ &have_invoke_virtual_or_interface_listeners_);
+ PotentiallyRemoveListenerFrom(kDexPcMoved,
+ events,
+ dex_pc_listeners_,
+ listener,
+ &have_dex_pc_listeners_);
+ PotentiallyRemoveListenerFrom(kFieldRead,
+ events,
+ field_read_listeners_,
+ listener,
+ &have_field_read_listeners_);
+ PotentiallyRemoveListenerFrom(kFieldWritten,
+ events,
+ field_write_listeners_,
+ listener,
+ &have_field_write_listeners_);
+ PotentiallyRemoveListenerFrom(kExceptionCaught,
+ events,
+ exception_caught_listeners_,
+ listener,
+ &have_exception_caught_listeners_);
UpdateInterpreterHandlerTable();
}
@@ -868,28 +866,24 @@ const void* Instrumentation::GetQuickCodeFor(ArtMethod* method, size_t pointer_s
void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
ArtMethod* method,
uint32_t dex_pc) const {
- auto it = method_entry_listeners_.begin();
- bool is_end = (it == method_entry_listeners_.end());
- // Implemented this way to prevent problems caused by modification of the list while iterating.
- while (!is_end) {
- InstrumentationListener* cur = *it;
- ++it;
- is_end = (it == method_entry_listeners_.end());
- cur->MethodEntered(thread, this_object, method, dex_pc);
+ if (HasMethodEntryListeners()) {
+ for (InstrumentationListener* listener : method_entry_listeners_) {
+ if (listener != nullptr) {
+ listener->MethodEntered(thread, this_object, method, dex_pc);
+ }
+ }
}
}
void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
ArtMethod* method,
uint32_t dex_pc, const JValue& return_value) const {
- auto it = method_exit_listeners_.begin();
- bool is_end = (it == method_exit_listeners_.end());
- // Implemented this way to prevent problems caused by modification of the list while iterating.
- while (!is_end) {
- InstrumentationListener* cur = *it;
- ++it;
- is_end = (it == method_exit_listeners_.end());
- cur->MethodExited(thread, this_object, method, dex_pc, return_value);
+ if (HasMethodExitListeners()) {
+ for (InstrumentationListener* listener : method_exit_listeners_) {
+ if (listener != nullptr) {
+ listener->MethodExited(thread, this_object, method, dex_pc, return_value);
+ }
+ }
}
}
@@ -898,7 +892,9 @@ void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_obj
uint32_t dex_pc) const {
if (HasMethodUnwindListeners()) {
for (InstrumentationListener* listener : method_unwind_listeners_) {
- listener->MethodUnwind(thread, this_object, method, dex_pc);
+ if (listener != nullptr) {
+ listener->MethodUnwind(thread, this_object, method, dex_pc);
+ }
}
}
}
@@ -906,16 +902,19 @@ void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_obj
void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
ArtMethod* method,
uint32_t dex_pc) const {
- std::shared_ptr<std::list<InstrumentationListener*>> original(dex_pc_listeners_);
- for (InstrumentationListener* listener : *original.get()) {
- listener->DexPcMoved(thread, this_object, method, dex_pc);
+ for (InstrumentationListener* listener : dex_pc_listeners_) {
+ if (listener != nullptr) {
+ listener->DexPcMoved(thread, this_object, method, dex_pc);
+ }
}
}
void Instrumentation::BackwardBranchImpl(Thread* thread, ArtMethod* method,
int32_t offset) const {
for (InstrumentationListener* listener : backward_branch_listeners_) {
- listener->BackwardBranch(thread, method, offset);
+ if (listener != nullptr) {
+ listener->BackwardBranch(thread, method, offset);
+ }
}
}
@@ -925,25 +924,29 @@ void Instrumentation::InvokeVirtualOrInterfaceImpl(Thread* thread,
uint32_t dex_pc,
ArtMethod* callee) const {
for (InstrumentationListener* listener : invoke_virtual_or_interface_listeners_) {
- listener->InvokeVirtualOrInterface(thread, this_object, caller, dex_pc, callee);
+ if (listener != nullptr) {
+ listener->InvokeVirtualOrInterface(thread, this_object, caller, dex_pc, callee);
+ }
}
}
void Instrumentation::FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
ArtMethod* method, uint32_t dex_pc,
ArtField* field) const {
- std::shared_ptr<std::list<InstrumentationListener*>> original(field_read_listeners_);
- for (InstrumentationListener* listener : *original.get()) {
- listener->FieldRead(thread, this_object, method, dex_pc, field);
+ for (InstrumentationListener* listener : field_read_listeners_) {
+ if (listener != nullptr) {
+ listener->FieldRead(thread, this_object, method, dex_pc, field);
+ }
}
}
void Instrumentation::FieldWriteEventImpl(Thread* thread, mirror::Object* this_object,
ArtMethod* method, uint32_t dex_pc,
ArtField* field, const JValue& field_value) const {
- std::shared_ptr<std::list<InstrumentationListener*>> original(field_write_listeners_);
- for (InstrumentationListener* listener : *original.get()) {
- listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value);
+ for (InstrumentationListener* listener : field_write_listeners_) {
+ if (listener != nullptr) {
+ listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value);
+ }
}
}
@@ -952,14 +955,24 @@ void Instrumentation::ExceptionCaughtEvent(Thread* thread,
if (HasExceptionCaughtListeners()) {
DCHECK_EQ(thread->GetException(), exception_object);
thread->ClearException();
- std::shared_ptr<std::list<InstrumentationListener*>> original(exception_caught_listeners_);
- for (InstrumentationListener* listener : *original.get()) {
- listener->ExceptionCaught(thread, exception_object);
+ for (InstrumentationListener* listener : exception_caught_listeners_) {
+ if (listener != nullptr) {
+ listener->ExceptionCaught(thread, exception_object);
+ }
}
thread->SetException(exception_object);
}
}
+// Computes a frame ID by ignoring inlined frames.
+size_t Instrumentation::ComputeFrameId(Thread* self,
+ size_t frame_depth,
+ size_t inlined_frames_before_frame) {
+ CHECK_GE(frame_depth, inlined_frames_before_frame);
+ size_t no_inline_depth = frame_depth - inlined_frames_before_frame;
+ return StackVisitor::ComputeNumFrames(self, kInstrumentationStackWalk) - no_inline_depth;
+}
+
static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
int delta)
SHARED_REQUIRES(Locks::mutator_lock_) {