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
41namespace art {
42namespace instrumentation {
43
44static 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
50bool 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()) {
60      const void* new_code;
61      if (uninstall) {
62        if (forced_interpret_only_ && !method->IsNative() && !method->IsProxyMethod()) {
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()) {
82      const void* new_code;
83      if (uninstall) {
84        if (forced_interpret_only_ && !method->IsNative() && !method->IsProxyMethod()) {
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.
104static 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.
181static 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
261void 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
291void 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
333void 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
379void 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
391const 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
404void 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
418void 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
432void 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
442void 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
455void 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
469static 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
481void 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
497uint64_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
552void 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
578std::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