• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InstallStubsClassVisitor(mirror::Class * klass,void * arg)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 
InstallStubsForClass(mirror::Class * klass)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.
InstrumentationInstallStack(Thread * thread,void * arg)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.
InstrumentationRestoreStack(Thread * thread,void * arg)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 
AddListener(InstrumentationListener * listener,uint32_t events)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 
RemoveListener(InstrumentationListener * listener,uint32_t events)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 
ConfigureStubs(bool require_entry_exit_stubs,bool require_interpreter)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 
UpdateMethodsCode(mirror::ArtMethod * method,const void * code) const379 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 
GetQuickCodeFor(const mirror::ArtMethod * method) const391 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 
MethodEnterEventImpl(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc) const404 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 
MethodExitEventImpl(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc,const JValue & return_value) const418 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 
MethodUnwindEvent(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc) const432 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 
DexPcMovedEventImpl(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc) const442 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 
ExceptionCaughtEvent(Thread * thread,const ThrowLocation & throw_location,mirror::ArtMethod * catch_method,uint32_t catch_dex_pc,mirror::Throwable * exception_object)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 
CheckStackDepth(Thread * self,const InstrumentationStackFrame & instrumentation_frame,int delta)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 
PushInstrumentationStackFrame(Thread * self,mirror::Object * this_object,mirror::ArtMethod * method,uintptr_t lr,bool interpreter_entry)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 
PopInstrumentationStackFrame(Thread * self,uintptr_t * return_pc,uint64_t gpr_result,uint64_t fpr_result)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 
PopMethodForUnwind(Thread * self,bool is_deoptimization) const552 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 
Dump() const578 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