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