Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "instrumentation.h"
     18 
     19 #include <sys/uio.h>
     20 
     21 #include "atomic_integer.h"
     22 #include "base/unix_file/fd_file.h"
     23 #include "class_linker.h"
     24 #include "debugger.h"
     25 #include "dex_file-inl.h"
     26 #include "mirror/art_method-inl.h"
     27 #include "mirror/class-inl.h"
     28 #include "mirror/dex_cache.h"
     29 #include "mirror/object_array-inl.h"
     30 #include "mirror/object-inl.h"
     31 #include "nth_caller_visitor.h"
     32 #if !defined(ART_USE_PORTABLE_COMPILER)
     33 #include "entrypoints/quick/quick_entrypoints.h"
     34 #endif
     35 #include "object_utils.h"
     36 #include "os.h"
     37 #include "scoped_thread_state_change.h"
     38 #include "thread.h"
     39 #include "thread_list.h"
     40 
     41 namespace art {
     42 namespace instrumentation {
     43 
     44 static bool InstallStubsClassVisitor(mirror::Class* klass, void* arg)
     45     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     46   Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
     47   return instrumentation->InstallStubsForClass(klass);
     48 }
     49 
     50 bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
     51   bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
     52   ClassLinker* class_linker = NULL;
     53   if (uninstall) {
     54     class_linker = Runtime::Current()->GetClassLinker();
     55   }
     56   bool is_initialized = klass->IsInitialized();
     57   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     58     mirror::ArtMethod* method = klass->GetDirectMethod(i);
     59     if (!method->IsAbstract() && !method->IsProxyMethod()) {
     60       const void* new_code;
     61       if (uninstall) {
     62         if (forced_interpret_only_ && !method->IsNative()) {
     63           new_code = GetCompiledCodeToInterpreterBridge();
     64         } else if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
     65           new_code = class_linker->GetOatCodeFor(method);
     66         } else {
     67           new_code = GetResolutionTrampoline(class_linker);
     68         }
     69       } else {  // !uninstall
     70         if (!interpreter_stubs_installed_ || method->IsNative()) {
     71           new_code = GetQuickInstrumentationEntryPoint();
     72         } else {
     73           new_code = GetCompiledCodeToInterpreterBridge();
     74         }
     75       }
     76       method->SetEntryPointFromCompiledCode(new_code);
     77     }
     78   }
     79   for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
     80     mirror::ArtMethod* method = klass->GetVirtualMethod(i);
     81     if (!method->IsAbstract() && !method->IsProxyMethod()) {
     82       const void* new_code;
     83       if (uninstall) {
     84         if (forced_interpret_only_ && !method->IsNative()) {
     85           new_code = GetCompiledCodeToInterpreterBridge();
     86         } else {
     87           new_code = class_linker->GetOatCodeFor(method);
     88         }
     89       } else {  // !uninstall
     90         if (!interpreter_stubs_installed_ || method->IsNative()) {
     91           new_code = GetQuickInstrumentationEntryPoint();
     92         } else {
     93           new_code = GetCompiledCodeToInterpreterBridge();
     94         }
     95       }
     96       method->SetEntryPointFromCompiledCode(new_code);
     97     }
     98   }
     99   return true;
    100 }
    101 
    102 // Places the instrumentation exit pc as the return PC for every quick frame. This also allows
    103 // deoptimization of quick frames to interpreter frames.
    104 static void InstrumentationInstallStack(Thread* thread, void* arg)
    105     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    106   struct InstallStackVisitor : public StackVisitor {
    107     InstallStackVisitor(Thread* thread, Context* context, uintptr_t instrumentation_exit_pc)
    108         : StackVisitor(thread, context),  instrumentation_stack_(thread->GetInstrumentationStack()),
    109           instrumentation_exit_pc_(instrumentation_exit_pc), last_return_pc_(0) {}
    110 
    111     virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    112       mirror::ArtMethod* m = GetMethod();
    113       if (GetCurrentQuickFrame() == NULL) {
    114         if (kVerboseInstrumentation) {
    115           LOG(INFO) << "  Ignoring a shadow frame. Frame " << GetFrameId()
    116               << " Method=" << PrettyMethod(m);
    117         }
    118         return true;  // Ignore shadow frames.
    119       }
    120       if (m == NULL) {
    121         if (kVerboseInstrumentation) {
    122           LOG(INFO) << "  Skipping upcall. Frame " << GetFrameId();
    123         }
    124         last_return_pc_ = 0;
    125         return true;  // Ignore upcalls.
    126       }
    127       if (m->IsRuntimeMethod()) {
    128         if (kVerboseInstrumentation) {
    129           LOG(INFO) << "  Skipping runtime method. Frame " << GetFrameId();
    130         }
    131         last_return_pc_ = GetReturnPc();
    132         return true;  // Ignore unresolved methods since they will be instrumented after resolution.
    133       }
    134       if (kVerboseInstrumentation) {
    135         LOG(INFO) << "  Installing exit stub in " << DescribeLocation();
    136       }
    137       uintptr_t return_pc = GetReturnPc();
    138       CHECK_NE(return_pc, instrumentation_exit_pc_);
    139       CHECK_NE(return_pc, 0U);
    140       InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, return_pc, GetFrameId(),
    141                                                       false);
    142       if (kVerboseInstrumentation) {
    143         LOG(INFO) << "Pushing frame " << instrumentation_frame.Dump();
    144       }
    145       instrumentation_stack_->push_back(instrumentation_frame);
    146       dex_pcs_.push_back(m->ToDexPc(last_return_pc_));
    147       SetReturnPc(instrumentation_exit_pc_);
    148       last_return_pc_ = return_pc;
    149       return true;  // Continue.
    150     }
    151     std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
    152     std::vector<uint32_t> dex_pcs_;
    153     const uintptr_t instrumentation_exit_pc_;
    154     uintptr_t last_return_pc_;
    155   };
    156   if (kVerboseInstrumentation) {
    157     std::string thread_name;
    158     thread->GetThreadName(thread_name);
    159     LOG(INFO) << "Installing exit stubs in " << thread_name;
    160   }
    161   UniquePtr<Context> context(Context::Create());
    162   uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
    163   InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
    164   visitor.WalkStack(true);
    165 
    166   // Create method enter events for all methods current on the thread's stack.
    167   Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
    168   typedef std::deque<InstrumentationStackFrame>::const_reverse_iterator It;
    169   for (It it = thread->GetInstrumentationStack()->rbegin(),
    170        end = thread->GetInstrumentationStack()->rend(); it != end; ++it) {
    171     mirror::Object* this_object = (*it).this_object_;
    172     mirror::ArtMethod* method = (*it).method_;
    173     uint32_t dex_pc = visitor.dex_pcs_.back();
    174     visitor.dex_pcs_.pop_back();
    175     instrumentation->MethodEnterEvent(thread, this_object, method, dex_pc);
    176   }
    177   thread->VerifyStack();
    178 }
    179 
    180 // Removes the instrumentation exit pc as the return PC for every quick frame.
    181 static void InstrumentationRestoreStack(Thread* thread, void* arg)
    182     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    183   struct RestoreStackVisitor : public StackVisitor {
    184     RestoreStackVisitor(Thread* thread, uintptr_t instrumentation_exit_pc,
    185                         Instrumentation* instrumentation)
    186         : StackVisitor(thread, NULL), thread_(thread),
    187           instrumentation_exit_pc_(instrumentation_exit_pc),
    188           instrumentation_(instrumentation),
    189           instrumentation_stack_(thread->GetInstrumentationStack()),
    190           frames_removed_(0) {}
    191 
    192     virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    193       if (instrumentation_stack_->size() == 0) {
    194         return false;  // Stop.
    195       }
    196       mirror::ArtMethod* m = GetMethod();
    197       if (GetCurrentQuickFrame() == NULL) {
    198         if (kVerboseInstrumentation) {
    199           LOG(INFO) << "  Ignoring a shadow frame. Frame " << GetFrameId() << " Method=" << PrettyMethod(m);
    200         }
    201         return true;  // Ignore shadow frames.
    202       }
    203       if (m == NULL) {
    204         if (kVerboseInstrumentation) {
    205           LOG(INFO) << "  Skipping upcall. Frame " << GetFrameId();
    206         }
    207         return true;  // Ignore upcalls.
    208       }
    209       bool removed_stub = false;
    210       // TODO: make this search more efficient?
    211       for (InstrumentationStackFrame instrumentation_frame : *instrumentation_stack_) {
    212         if (instrumentation_frame.frame_id_ == GetFrameId()) {
    213           if (kVerboseInstrumentation) {
    214             LOG(INFO) << "  Removing exit stub in " << DescribeLocation();
    215           }
    216           if (instrumentation_frame.interpreter_entry_) {
    217             CHECK(m == Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
    218           } else {
    219             CHECK(m == instrumentation_frame.method_) << PrettyMethod(m);
    220           }
    221           SetReturnPc(instrumentation_frame.return_pc_);
    222           // Create the method exit events. As the methods didn't really exit the result is 0.
    223           instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m,
    224                                             GetDexPc(), JValue());
    225           frames_removed_++;
    226           removed_stub = true;
    227           break;
    228         }
    229       }
    230       if (!removed_stub) {
    231         if (kVerboseInstrumentation) {
    232           LOG(INFO) << "  No exit stub in " << DescribeLocation();
    233         }
    234       }
    235       return true;  // Continue.
    236     }
    237     Thread* const thread_;
    238     const uintptr_t instrumentation_exit_pc_;
    239     Instrumentation* const instrumentation_;
    240     std::deque<instrumentation::InstrumentationStackFrame>* const instrumentation_stack_;
    241     size_t frames_removed_;
    242   };
    243   if (kVerboseInstrumentation) {
    244     std::string thread_name;
    245     thread->GetThreadName(thread_name);
    246     LOG(INFO) << "Removing exit stubs in " << thread_name;
    247   }
    248   std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
    249   if (stack->size() > 0) {
    250     Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
    251     uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
    252     RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
    253     visitor.WalkStack(true);
    254     CHECK_EQ(visitor.frames_removed_, stack->size());
    255     while (stack->size() > 0) {
    256       stack->pop_front();
    257     }
    258   }
    259 }
    260 
    261 void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
    262   Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
    263   bool require_entry_exit_stubs = false;
    264   bool require_interpreter = false;
    265   if ((events & kMethodEntered) != 0) {
    266     method_entry_listeners_.push_back(listener);
    267     require_entry_exit_stubs = true;
    268     have_method_entry_listeners_ = true;
    269   }
    270   if ((events & kMethodExited) != 0) {
    271     method_exit_listeners_.push_back(listener);
    272     require_entry_exit_stubs = true;
    273     have_method_exit_listeners_ = true;
    274   }
    275   if ((events & kMethodUnwind) != 0) {
    276     method_unwind_listeners_.push_back(listener);
    277     have_method_unwind_listeners_ = true;
    278   }
    279   if ((events & kDexPcMoved) != 0) {
    280     dex_pc_listeners_.push_back(listener);
    281     require_interpreter = true;
    282     have_dex_pc_listeners_ = true;
    283   }
    284   if ((events & kExceptionCaught) != 0) {
    285     exception_caught_listeners_.push_back(listener);
    286     have_exception_caught_listeners_ = true;
    287   }
    288   ConfigureStubs(require_entry_exit_stubs, require_interpreter);
    289 }
    290 
    291 void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
    292   Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
    293   bool require_entry_exit_stubs = false;
    294   bool require_interpreter = false;
    295 
    296   if ((events & kMethodEntered) != 0) {
    297     bool contains = std::find(method_entry_listeners_.begin(), method_entry_listeners_.end(),
    298                               listener) != method_entry_listeners_.end();
    299     if (contains) {
    300       method_entry_listeners_.remove(listener);
    301     }
    302     have_method_entry_listeners_ = method_entry_listeners_.size() > 0;
    303     require_entry_exit_stubs |= have_method_entry_listeners_;
    304   }
    305   if ((events & kMethodExited) != 0) {
    306     bool contains = std::find(method_exit_listeners_.begin(), method_exit_listeners_.end(),
    307                               listener) != method_exit_listeners_.end();
    308     if (contains) {
    309       method_exit_listeners_.remove(listener);
    310     }
    311     have_method_exit_listeners_ = method_exit_listeners_.size() > 0;
    312     require_entry_exit_stubs |= have_method_exit_listeners_;
    313   }
    314   if ((events & kMethodUnwind) != 0) {
    315     method_unwind_listeners_.remove(listener);
    316   }
    317   if ((events & kDexPcMoved) != 0) {
    318     bool contains = std::find(dex_pc_listeners_.begin(), dex_pc_listeners_.end(),
    319                               listener) != dex_pc_listeners_.end();
    320     if (contains) {
    321       dex_pc_listeners_.remove(listener);
    322     }
    323     have_dex_pc_listeners_ = dex_pc_listeners_.size() > 0;
    324     require_interpreter |= have_dex_pc_listeners_;
    325   }
    326   if ((events & kExceptionCaught) != 0) {
    327     exception_caught_listeners_.remove(listener);
    328     have_exception_caught_listeners_ = exception_caught_listeners_.size() > 0;
    329   }
    330   ConfigureStubs(require_entry_exit_stubs, require_interpreter);
    331 }
    332 
    333 void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter) {
    334   interpret_only_ = require_interpreter || forced_interpret_only_;
    335   // Compute what level of instrumentation is required and compare to current.
    336   int desired_level, current_level;
    337   if (require_interpreter) {
    338     desired_level = 2;
    339   } else if (require_entry_exit_stubs) {
    340     desired_level = 1;
    341   } else {
    342     desired_level = 0;
    343   }
    344   if (interpreter_stubs_installed_) {
    345     current_level = 2;
    346   } else if (entry_exit_stubs_installed_) {
    347     current_level = 1;
    348   } else {
    349     current_level = 0;
    350   }
    351   if (desired_level == current_level) {
    352     // We're already set.
    353     return;
    354   }
    355   Thread* self = Thread::Current();
    356   Runtime* runtime = Runtime::Current();
    357   Locks::thread_list_lock_->AssertNotHeld(self);
    358   if (desired_level > 0) {
    359     if (require_interpreter) {
    360       interpreter_stubs_installed_ = true;
    361     } else {
    362       CHECK(require_entry_exit_stubs);
    363       entry_exit_stubs_installed_ = true;
    364     }
    365     runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
    366     instrumentation_stubs_installed_ = true;
    367     MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
    368     runtime->GetThreadList()->ForEach(InstrumentationInstallStack, this);
    369   } else {
    370     interpreter_stubs_installed_ = false;
    371     entry_exit_stubs_installed_ = false;
    372     runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
    373     instrumentation_stubs_installed_ = false;
    374     MutexLock mu(self, *Locks::thread_list_lock_);
    375     Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
    376   }
    377 }
    378 
    379 void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const {
    380   if (LIKELY(!instrumentation_stubs_installed_)) {
    381     method->SetEntryPointFromCompiledCode(code);
    382   } else {
    383     if (!interpreter_stubs_installed_ || method->IsNative()) {
    384       method->SetEntryPointFromCompiledCode(GetQuickInstrumentationEntryPoint());
    385     } else {
    386       method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge());
    387     }
    388   }
    389 }
    390 
    391 const void* Instrumentation::GetQuickCodeFor(const mirror::ArtMethod* method) const {
    392   Runtime* runtime = Runtime::Current();
    393   if (LIKELY(!instrumentation_stubs_installed_)) {
    394     const void* code = method->GetEntryPointFromCompiledCode();
    395     DCHECK(code != NULL);
    396     if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker()) &&
    397                code != GetQuickToInterpreterBridge())) {
    398       return code;
    399     }
    400   }
    401   return runtime->GetClassLinker()->GetOatCodeFor(method);
    402 }
    403 
    404 void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
    405                                            const mirror::ArtMethod* method,
    406                                            uint32_t dex_pc) const {
    407   auto it = method_entry_listeners_.begin();
    408   bool is_end = (it == method_entry_listeners_.end());
    409   // Implemented this way to prevent problems caused by modification of the list while iterating.
    410   while (!is_end) {
    411     InstrumentationListener* cur = *it;
    412     ++it;
    413     is_end = (it == method_entry_listeners_.end());
    414     cur->MethodEntered(thread, this_object, method, dex_pc);
    415   }
    416 }
    417 
    418 void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
    419                                           const mirror::ArtMethod* method,
    420                                           uint32_t dex_pc, const JValue& return_value) const {
    421   auto it = method_exit_listeners_.begin();
    422   bool is_end = (it == method_exit_listeners_.end());
    423   // Implemented this way to prevent problems caused by modification of the list while iterating.
    424   while (!is_end) {
    425     InstrumentationListener* cur = *it;
    426     ++it;
    427     is_end = (it == method_exit_listeners_.end());
    428     cur->MethodExited(thread, this_object, method, dex_pc, return_value);
    429   }
    430 }
    431 
    432 void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
    433                                         const mirror::ArtMethod* method,
    434                                         uint32_t dex_pc) const {
    435   if (have_method_unwind_listeners_) {
    436     for (InstrumentationListener* listener : method_unwind_listeners_) {
    437       listener->MethodUnwind(thread, method, dex_pc);
    438     }
    439   }
    440 }
    441 
    442 void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
    443                                           const mirror::ArtMethod* method,
    444                                           uint32_t dex_pc) const {
    445   // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an
    446   // action where it can remove itself as a listener and break the iterator. The copy only works
    447   // around the problem and in general we may have to move to something like reference counting to
    448   // ensure listeners are deleted correctly.
    449   std::list<InstrumentationListener*> copy(dex_pc_listeners_);
    450   for (InstrumentationListener* listener : copy) {
    451     listener->DexPcMoved(thread, this_object, method, dex_pc);
    452   }
    453 }
    454 
    455 void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
    456                                            mirror::ArtMethod* catch_method,
    457                                            uint32_t catch_dex_pc,
    458                                            mirror::Throwable* exception_object) {
    459   if (have_exception_caught_listeners_) {
    460     DCHECK_EQ(thread->GetException(NULL), exception_object);
    461     thread->ClearException();
    462     for (InstrumentationListener* listener : exception_caught_listeners_) {
    463       listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
    464     }
    465     thread->SetException(throw_location, exception_object);
    466   }
    467 }
    468 
    469 static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
    470                             int delta)
    471     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    472   size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
    473   if (frame_id != instrumentation_frame.frame_id_) {
    474     LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
    475         << instrumentation_frame.frame_id_;
    476     StackVisitor::DescribeStack(self);
    477     CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
    478   }
    479 }
    480 
    481 void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
    482                                                     mirror::ArtMethod* method,
    483                                                     uintptr_t lr, bool interpreter_entry) {
    484   // We have a callee-save frame meaning this value is guaranteed to never be 0.
    485   size_t frame_id = StackVisitor::ComputeNumFrames(self);
    486   std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
    487   if (kVerboseInstrumentation) {
    488     LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << reinterpret_cast<void*>(lr);
    489   }
    490   instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
    491                                                                    frame_id, interpreter_entry);
    492   stack->push_front(instrumentation_frame);
    493 
    494   MethodEnterEvent(self, this_object, method, 0);
    495 }
    496 
    497 uint64_t Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
    498                                                        uint64_t gpr_result, uint64_t fpr_result) {
    499   // Do the pop.
    500   std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
    501   CHECK_GT(stack->size(), 0U);
    502   InstrumentationStackFrame instrumentation_frame = stack->front();
    503   stack->pop_front();
    504 
    505   // Set return PC and check the sanity of the stack.
    506   *return_pc = instrumentation_frame.return_pc_;
    507   CheckStackDepth(self, instrumentation_frame, 0);
    508 
    509   mirror::ArtMethod* method = instrumentation_frame.method_;
    510   char return_shorty = MethodHelper(method).GetShorty()[0];
    511   JValue return_value;
    512   if (return_shorty == 'V') {
    513     return_value.SetJ(0);
    514   } else if (return_shorty == 'F' || return_shorty == 'D') {
    515     return_value.SetJ(fpr_result);
    516   } else {
    517     return_value.SetJ(gpr_result);
    518   }
    519   // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
    520   //       return_pc.
    521   uint32_t dex_pc = DexFile::kDexNoIndex;
    522   mirror::Object* this_object = instrumentation_frame.this_object_;
    523   MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
    524 
    525   bool deoptimize = false;
    526   if (interpreter_stubs_installed_) {
    527     // Deoptimize unless we're returning to an upcall.
    528     NthCallerVisitor visitor(self, 1, true);
    529     visitor.WalkStack(true);
    530     deoptimize = visitor.caller != NULL;
    531     if (deoptimize && kVerboseInstrumentation) {
    532       LOG(INFO) << "Deoptimizing into " << PrettyMethod(visitor.caller);
    533     }
    534   }
    535   if (deoptimize) {
    536     if (kVerboseInstrumentation) {
    537       LOG(INFO) << "Deoptimizing from " << PrettyMethod(method)
    538           << " result is " << std::hex << return_value.GetJ();
    539     }
    540     self->SetDeoptimizationReturnValue(return_value);
    541     return static_cast<uint64_t>(GetQuickDeoptimizationEntryPoint()) |
    542         (static_cast<uint64_t>(*return_pc) << 32);
    543   } else {
    544     if (kVerboseInstrumentation) {
    545       LOG(INFO) << "Returning from " << PrettyMethod(method)
    546                 << " to PC " << reinterpret_cast<void*>(*return_pc);
    547     }
    548     return *return_pc;
    549   }
    550 }
    551 
    552 void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
    553   // Do the pop.
    554   std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
    555   CHECK_GT(stack->size(), 0U);
    556   InstrumentationStackFrame instrumentation_frame = stack->front();
    557   // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
    558   stack->pop_front();
    559 
    560   mirror::ArtMethod* method = instrumentation_frame.method_;
    561   if (is_deoptimization) {
    562     if (kVerboseInstrumentation) {
    563       LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
    564     }
    565   } else {
    566     if (kVerboseInstrumentation) {
    567       LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
    568     }
    569 
    570     // Notify listeners of method unwind.
    571     // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
    572     //       return_pc.
    573     uint32_t dex_pc = DexFile::kDexNoIndex;
    574     MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
    575   }
    576 }
    577 
    578 std::string InstrumentationStackFrame::Dump() const {
    579   std::ostringstream os;
    580   os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
    581       << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
    582   return os.str();
    583 }
    584 
    585 }  // namespace instrumentation
    586 }  // namespace art
    587