instrumentation.cc revision 166db04e259ca51838c311891598664deeed85ad
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/class-inl.h"
27#include "mirror/dex_cache.h"
28#include "mirror/abstract_method-inl.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::AbstractMethod* 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 = GetInterpreterEntryPoint();
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 = GetInstrumentationEntryPoint();
72        } else {
73          new_code = GetInterpreterEntryPoint();
74        }
75      }
76      method->SetEntryPointFromCompiledCode(new_code);
77    }
78  }
79  for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
80    mirror::AbstractMethod* 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 = GetInterpreterEntryPoint();
86        } else {
87          new_code = class_linker->GetOatCodeFor(method);
88        }
89      } else {  // !uninstall
90        if (!interpreter_stubs_installed_ || method->IsNative()) {
91          new_code = GetInstrumentationEntryPoint();
92        } else {
93          new_code = GetInterpreterEntryPoint();
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::AbstractMethod* 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 = GetInstrumentationExitPc();
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::AbstractMethod* 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::AbstractMethod* 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      typedef std::deque<instrumentation::InstrumentationStackFrame>::const_iterator It;  // TODO: C++0x auto
210      bool removed_stub = false;
211      // TODO: make this search more efficient?
212      for (It it = instrumentation_stack_->begin(), end = instrumentation_stack_->end(); it != end;
213          ++it) {
214        InstrumentationStackFrame instrumentation_frame =  *it;
215        if (instrumentation_frame.frame_id_ == GetFrameId()) {
216          if (kVerboseInstrumentation) {
217            LOG(INFO) << "  Removing exit stub in " << DescribeLocation();
218          }
219          if (instrumentation_frame.interpreter_entry_) {
220            CHECK(m == Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
221          } else {
222            CHECK(m == instrumentation_frame.method_) << PrettyMethod(m);
223          }
224          SetReturnPc(instrumentation_frame.return_pc_);
225          // Create the method exit events. As the methods didn't really exit the result is 0.
226          instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m,
227                                            GetDexPc(), JValue());
228          frames_removed_++;
229          removed_stub = true;
230          break;
231        }
232      }
233      if (!removed_stub) {
234        if (kVerboseInstrumentation) {
235          LOG(INFO) << "  No exit stub in " << DescribeLocation();
236        }
237      }
238      return true;  // Continue.
239    }
240    Thread* const thread_;
241    const uintptr_t instrumentation_exit_pc_;
242    Instrumentation* const instrumentation_;
243    std::deque<instrumentation::InstrumentationStackFrame>* const instrumentation_stack_;
244    size_t frames_removed_;
245  };
246  if (kVerboseInstrumentation) {
247    std::string thread_name;
248    thread->GetThreadName(thread_name);
249    LOG(INFO) << "Removing exit stubs in " << thread_name;
250  }
251  std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
252  if (stack->size() > 0) {
253    Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
254    uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
255    RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
256    visitor.WalkStack(true);
257    CHECK_EQ(visitor.frames_removed_, stack->size());
258    while (stack->size() > 0) {
259      stack->pop_front();
260    }
261  }
262}
263
264void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
265  Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
266  bool require_entry_exit_stubs = false;
267  bool require_interpreter = false;
268  if ((events & kMethodEntered) != 0) {
269    method_entry_listeners_.push_back(listener);
270    require_entry_exit_stubs = true;
271    have_method_entry_listeners_ = true;
272  }
273  if ((events & kMethodExited) != 0) {
274    method_exit_listeners_.push_back(listener);
275    require_entry_exit_stubs = true;
276    have_method_exit_listeners_ = true;
277  }
278  if ((events & kMethodUnwind) != 0) {
279    method_unwind_listeners_.push_back(listener);
280    have_method_unwind_listeners_ = true;
281  }
282  if ((events & kDexPcMoved) != 0) {
283    dex_pc_listeners_.push_back(listener);
284    require_interpreter = true;
285    have_dex_pc_listeners_ = true;
286  }
287  if ((events & kExceptionCaught) != 0) {
288    exception_caught_listeners_.push_back(listener);
289    have_exception_caught_listeners_ = true;
290  }
291  ConfigureStubs(require_entry_exit_stubs, require_interpreter);
292}
293
294void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
295  Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
296  bool require_entry_exit_stubs = false;
297  bool require_interpreter = false;
298
299  if ((events & kMethodEntered) != 0) {
300    bool contains = std::find(method_entry_listeners_.begin(), method_entry_listeners_.end(),
301                              listener) != method_entry_listeners_.end();
302    if (contains) {
303      method_entry_listeners_.remove(listener);
304    }
305    have_method_entry_listeners_ = method_entry_listeners_.size() > 0;
306    require_entry_exit_stubs |= have_method_entry_listeners_;
307  }
308  if ((events & kMethodExited) != 0) {
309    bool contains = std::find(method_exit_listeners_.begin(), method_exit_listeners_.end(),
310                              listener) != method_exit_listeners_.end();
311    if (contains) {
312      method_exit_listeners_.remove(listener);
313    }
314    have_method_exit_listeners_ = method_exit_listeners_.size() > 0;
315    require_entry_exit_stubs |= have_method_exit_listeners_;
316  }
317  if ((events & kMethodUnwind) != 0) {
318    method_unwind_listeners_.remove(listener);
319  }
320  if ((events & kDexPcMoved) != 0) {
321    bool contains = std::find(dex_pc_listeners_.begin(), dex_pc_listeners_.end(),
322                              listener) != dex_pc_listeners_.end();
323    if (contains) {
324      dex_pc_listeners_.remove(listener);
325    }
326    have_dex_pc_listeners_ = dex_pc_listeners_.size() > 0;
327    require_interpreter |= have_dex_pc_listeners_;
328  }
329  if ((events & kExceptionCaught) != 0) {
330    exception_caught_listeners_.remove(listener);
331    have_exception_caught_listeners_ = exception_caught_listeners_.size() > 0;
332  }
333  ConfigureStubs(require_entry_exit_stubs, require_interpreter);
334}
335
336void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter) {
337  interpret_only_ = require_interpreter || forced_interpret_only_;
338  // Compute what level of instrumentation is required and compare to current.
339  int desired_level, current_level;
340  if (require_interpreter) {
341    desired_level = 2;
342  } else if (require_entry_exit_stubs) {
343    desired_level = 1;
344  } else {
345    desired_level = 0;
346  }
347  if (interpreter_stubs_installed_) {
348    current_level = 2;
349  } else if (entry_exit_stubs_installed_) {
350    current_level = 1;
351  } else {
352    current_level = 0;
353  }
354  if (desired_level == current_level) {
355    // We're already set.
356    return;
357  }
358  Thread* self = Thread::Current();
359  Runtime* runtime = Runtime::Current();
360  Locks::thread_list_lock_->AssertNotHeld(self);
361  if (desired_level > 0) {
362    if (require_interpreter) {
363      interpreter_stubs_installed_ = true;
364    } else {
365      CHECK(require_entry_exit_stubs);
366      entry_exit_stubs_installed_ = true;
367    }
368    runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
369    instrumentation_stubs_installed_ = true;
370    MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
371    runtime->GetThreadList()->ForEach(InstrumentationInstallStack, this);
372  } else {
373    interpreter_stubs_installed_ = false;
374    entry_exit_stubs_installed_ = false;
375    runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
376    instrumentation_stubs_installed_ = false;
377    MutexLock mu(self, *Locks::thread_list_lock_);
378    Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
379  }
380}
381
382void Instrumentation::UpdateMethodsCode(mirror::AbstractMethod* method, const void* code) const {
383  if (LIKELY(!instrumentation_stubs_installed_)) {
384    method->SetEntryPointFromCompiledCode(code);
385  } else {
386    if (!interpreter_stubs_installed_ || method->IsNative()) {
387      method->SetEntryPointFromCompiledCode(GetInstrumentationEntryPoint());
388    } else {
389      method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
390    }
391  }
392}
393
394const void* Instrumentation::GetQuickCodeFor(const mirror::AbstractMethod* method) const {
395  Runtime* runtime = Runtime::Current();
396  if (LIKELY(!instrumentation_stubs_installed_)) {
397    const void* code = method->GetEntryPointFromCompiledCode();
398    DCHECK(code != NULL);
399    if (LIKELY(code != GetResolutionTrampoline(runtime->GetClassLinker()) &&
400               code != GetInterpreterEntryPoint())) {
401      return code;
402    }
403  }
404  return runtime->GetClassLinker()->GetOatCodeFor(method);
405}
406
407void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
408                                           const mirror::AbstractMethod* method,
409                                           uint32_t dex_pc) const {
410  typedef std::list<InstrumentationListener*>::const_iterator It;  // TODO: C++0x auto
411  It it = method_entry_listeners_.begin();
412  bool is_end = (it == method_entry_listeners_.end());
413  // Implemented this way to prevent problems caused by modification of the list while iterating.
414  while (!is_end) {
415    InstrumentationListener* cur = *it;
416    ++it;
417    is_end = (it == method_entry_listeners_.end());
418    cur->MethodEntered(thread, this_object, method, dex_pc);
419  }
420}
421
422void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
423                                          const mirror::AbstractMethod* method,
424                                          uint32_t dex_pc, const JValue& return_value) const {
425  typedef std::list<InstrumentationListener*>::const_iterator It;  // TODO: C++0x auto
426  It it = method_exit_listeners_.begin();
427  bool is_end = (it == method_exit_listeners_.end());
428  // Implemented this way to prevent problems caused by modification of the list while iterating.
429  while (!is_end) {
430    InstrumentationListener* cur = *it;
431    ++it;
432    is_end = (it == method_exit_listeners_.end());
433    cur->MethodExited(thread, this_object, method, dex_pc, return_value);
434  }
435}
436
437void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
438                                        const mirror::AbstractMethod* method,
439                                        uint32_t dex_pc) const {
440  if (have_method_unwind_listeners_) {
441    typedef std::list<InstrumentationListener*>::const_iterator It;  // TODO: C++0x auto
442    for (It it = method_unwind_listeners_.begin(), end = method_unwind_listeners_.end(); it != end;
443        ++it) {
444      (*it)->MethodUnwind(thread, method, dex_pc);
445    }
446  }
447}
448
449void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
450                                          const mirror::AbstractMethod* method,
451                                          uint32_t dex_pc) const {
452  // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an
453  // action where it can remove itself as a listener and break the iterator. The copy only works
454  // around the problem and in general we may have to move to something like reference counting to
455  // ensure listeners are deleted correctly.
456  std::list<InstrumentationListener*> copy(dex_pc_listeners_);
457  typedef std::list<InstrumentationListener*>::const_iterator It;  // TODO: C++0x auto
458  for (It it = copy.begin(), end = copy.end(); it != end; ++it) {
459    (*it)->DexPcMoved(thread, this_object, method, dex_pc);
460  }
461}
462
463void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
464                                           mirror::AbstractMethod* catch_method,
465                                           uint32_t catch_dex_pc,
466                                           mirror::Throwable* exception_object) {
467  if (have_exception_caught_listeners_) {
468    DCHECK_EQ(thread->GetException(NULL), exception_object);
469    thread->ClearException();
470    typedef std::list<InstrumentationListener*>::const_iterator It;  // TODO: C++0x auto
471    for (It it = exception_caught_listeners_.begin(), end = exception_caught_listeners_.end();
472        it != end; ++it) {
473      (*it)->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
474    }
475    thread->SetException(throw_location, exception_object);
476  }
477}
478
479static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
480                            int delta)
481    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
482  size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
483  if (frame_id != instrumentation_frame.frame_id_) {
484    LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
485        << instrumentation_frame.frame_id_;
486    StackVisitor::DescribeStack(self);
487    CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
488  }
489}
490
491void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
492                                                    mirror::AbstractMethod* method,
493                                                    uintptr_t lr, bool interpreter_entry) {
494  // We have a callee-save frame meaning this value is guaranteed to never be 0.
495  size_t frame_id = StackVisitor::ComputeNumFrames(self);
496  std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
497  if (kVerboseInstrumentation) {
498    LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << reinterpret_cast<void*>(lr);
499  }
500  instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
501                                                                   frame_id, interpreter_entry);
502  stack->push_front(instrumentation_frame);
503
504  MethodEnterEvent(self, this_object, method, 0);
505}
506
507uint64_t Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
508                                                       uint64_t gpr_result, uint64_t fpr_result) {
509  // Do the pop.
510  std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
511  CHECK_GT(stack->size(), 0U);
512  InstrumentationStackFrame instrumentation_frame = stack->front();
513  stack->pop_front();
514
515  // Set return PC and check the sanity of the stack.
516  *return_pc = instrumentation_frame.return_pc_;
517  CheckStackDepth(self, instrumentation_frame, 0);
518
519  mirror::AbstractMethod* method = instrumentation_frame.method_;
520  char return_shorty = MethodHelper(method).GetShorty()[0];
521  JValue return_value;
522  if (return_shorty == 'V') {
523    return_value.SetJ(0);
524  } else if (return_shorty == 'F' || return_shorty == 'D') {
525    return_value.SetJ(fpr_result);
526  } else {
527    return_value.SetJ(gpr_result);
528  }
529  // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
530  //       return_pc.
531  uint32_t dex_pc = DexFile::kDexNoIndex;
532  mirror::Object* this_object = instrumentation_frame.this_object_;
533  MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
534
535  bool deoptimize = false;
536  if (interpreter_stubs_installed_) {
537    // Deoptimize unless we're returning to an upcall.
538    NthCallerVisitor visitor(self, 1, true);
539    visitor.WalkStack(true);
540    deoptimize = visitor.caller != NULL;
541    if (deoptimize && kVerboseInstrumentation) {
542      LOG(INFO) << "Deoptimizing into " << PrettyMethod(visitor.caller);
543    }
544  }
545  if (deoptimize) {
546    if (kVerboseInstrumentation) {
547      LOG(INFO) << "Deoptimizing from " << PrettyMethod(method)
548          << " result is " << std::hex << return_value.GetJ();
549    }
550    self->SetDeoptimizationReturnValue(return_value);
551    return static_cast<uint64_t>(GetDeoptimizationEntryPoint()) |
552        (static_cast<uint64_t>(*return_pc) << 32);
553  } else {
554    if (kVerboseInstrumentation) {
555      LOG(INFO) << "Returning from " << PrettyMethod(method)
556                << " to PC " << reinterpret_cast<void*>(*return_pc);
557    }
558    return *return_pc;
559  }
560}
561
562void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
563  // Do the pop.
564  std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
565  CHECK_GT(stack->size(), 0U);
566  InstrumentationStackFrame instrumentation_frame = stack->front();
567  // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
568  stack->pop_front();
569
570  mirror::AbstractMethod* method = instrumentation_frame.method_;
571  if (is_deoptimization) {
572    if (kVerboseInstrumentation) {
573      LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
574    }
575  } else {
576    if (kVerboseInstrumentation) {
577      LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
578    }
579
580    // Notify listeners of method unwind.
581    // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
582    //       return_pc.
583    uint32_t dex_pc = DexFile::kDexNoIndex;
584    MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
585  }
586}
587
588std::string InstrumentationStackFrame::Dump() const {
589  std::ostringstream os;
590  os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
591      << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
592  return os.str();
593}
594
595}  // namespace instrumentation
596}  // namespace art
597