diff options
Diffstat (limited to 'runtime/instrumentation.cc')
| -rw-r--r-- | runtime/instrumentation.cc | 355 |
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_) { |