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 "arch/context.h"
22 #include "atomic.h"
23 #include "base/unix_file/fd_file.h"
24 #include "class_linker.h"
25 #include "debugger.h"
26 #include "dex_file-inl.h"
27 #include "entrypoints/quick/quick_alloc_entrypoints.h"
28 #include "gc_root-inl.h"
29 #include "interpreter/interpreter.h"
30 #include "mirror/art_method-inl.h"
31 #include "mirror/class-inl.h"
32 #include "mirror/dex_cache.h"
33 #include "mirror/object_array-inl.h"
34 #include "mirror/object-inl.h"
35 #include "nth_caller_visitor.h"
36 #if !defined(ART_USE_PORTABLE_COMPILER)
37 #include "entrypoints/quick/quick_entrypoints.h"
38 #endif
39 #include "os.h"
40 #include "scoped_thread_state_change.h"
41 #include "thread.h"
42 #include "thread_list.h"
43
44 namespace art {
45
46 namespace instrumentation {
47
48 const bool kVerboseInstrumentation = false;
49
50 // Do we want to deoptimize for method entry and exit listeners or just try to intercept
51 // invocations? Deoptimization forces all code to run in the interpreter and considerably hurts the
52 // application's performance.
53 static constexpr bool kDeoptimizeForAccurateMethodEntryExitListeners = true;
54
InstallStubsClassVisitor(mirror::Class * klass,void * arg)55 static bool InstallStubsClassVisitor(mirror::Class* klass, void* arg)
56 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
57 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
58 return instrumentation->InstallStubsForClass(klass);
59 }
60
Instrumentation()61 Instrumentation::Instrumentation()
62 : instrumentation_stubs_installed_(false), entry_exit_stubs_installed_(false),
63 interpreter_stubs_installed_(false),
64 interpret_only_(false), forced_interpret_only_(false),
65 have_method_entry_listeners_(false), have_method_exit_listeners_(false),
66 have_method_unwind_listeners_(false), have_dex_pc_listeners_(false),
67 have_field_read_listeners_(false), have_field_write_listeners_(false),
68 have_exception_caught_listeners_(false),
69 deoptimized_methods_lock_("deoptimized methods lock"),
70 deoptimization_enabled_(false),
71 interpreter_handler_table_(kMainHandlerTable),
72 quick_alloc_entry_points_instrumentation_counter_(0) {
73 }
74
InstallStubsForClass(mirror::Class * klass)75 bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
76 for (size_t i = 0, e = klass->NumDirectMethods(); i < e; i++) {
77 InstallStubsForMethod(klass->GetDirectMethod(i));
78 }
79 for (size_t i = 0, e = klass->NumVirtualMethods(); i < e; i++) {
80 InstallStubsForMethod(klass->GetVirtualMethod(i));
81 }
82 return true;
83 }
84
UpdateEntrypoints(mirror::ArtMethod * method,const void * quick_code,const void * portable_code,bool have_portable_code)85 static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code,
86 const void* portable_code, bool have_portable_code)
87 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
88 #if defined(ART_USE_PORTABLE_COMPILER)
89 method->SetEntryPointFromPortableCompiledCode(portable_code);
90 #endif
91 method->SetEntryPointFromQuickCompiledCode(quick_code);
92 bool portable_enabled = method->IsPortableCompiled();
93 if (have_portable_code && !portable_enabled) {
94 method->SetIsPortableCompiled();
95 } else if (portable_enabled) {
96 method->ClearIsPortableCompiled();
97 }
98 if (!method->IsResolutionMethod()) {
99 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
100 if (quick_code == GetQuickToInterpreterBridge() ||
101 quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
102 (quick_code == class_linker->GetQuickResolutionTrampoline() &&
103 Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()
104 && !method->IsNative() && !method->IsProxyMethod())) {
105 if (kIsDebugBuild) {
106 if (quick_code == GetQuickToInterpreterBridge()) {
107 #if defined(ART_USE_PORTABLE_COMPILER)
108 DCHECK(portable_code == GetPortableToInterpreterBridge());
109 #endif
110 } else if (quick_code == class_linker->GetQuickResolutionTrampoline()) {
111 #if defined(ART_USE_PORTABLE_COMPILER)
112 DCHECK(portable_code == class_linker->GetPortableResolutionTrampoline());
113 #endif
114 }
115 }
116 DCHECK(!method->IsNative()) << PrettyMethod(method);
117 DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
118 method->SetEntryPointFromInterpreter(art::interpreter::artInterpreterToInterpreterBridge);
119 } else {
120 method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
121 }
122 }
123 }
124
InstallStubsForMethod(mirror::ArtMethod * method)125 void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) {
126 if (method->IsAbstract() || method->IsProxyMethod()) {
127 // Do not change stubs for these methods.
128 return;
129 }
130 // Don't stub Proxy.<init>. Note that the Proxy class itself is not a proxy class.
131 if (method->IsConstructor() &&
132 method->GetDeclaringClass()->DescriptorEquals("Ljava/lang/reflect/Proxy;")) {
133 return;
134 }
135 const void* new_portable_code;
136 const void* new_quick_code;
137 bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
138 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
139 bool is_class_initialized = method->GetDeclaringClass()->IsInitialized();
140 bool have_portable_code = false;
141 #if !defined(ART_USE_PORTABLE_COMPILER)
142 new_portable_code = nullptr;
143 #endif
144 if (uninstall) {
145 if ((forced_interpret_only_ || IsDeoptimized(method)) && !method->IsNative()) {
146 #if defined(ART_USE_PORTABLE_COMPILER)
147 new_portable_code = GetPortableToInterpreterBridge();
148 #endif
149 new_quick_code = GetQuickToInterpreterBridge();
150 } else if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
151 #if defined(ART_USE_PORTABLE_COMPILER)
152 new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
153 #endif
154 new_quick_code = class_linker->GetQuickOatCodeFor(method);
155 } else {
156 #if defined(ART_USE_PORTABLE_COMPILER)
157 new_portable_code = class_linker->GetPortableResolutionTrampoline();
158 #endif
159 new_quick_code = class_linker->GetQuickResolutionTrampoline();
160 }
161 } else { // !uninstall
162 if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) &&
163 !method->IsNative()) {
164 #if defined(ART_USE_PORTABLE_COMPILER)
165 new_portable_code = GetPortableToInterpreterBridge();
166 #endif
167 new_quick_code = GetQuickToInterpreterBridge();
168 } else {
169 // Do not overwrite resolution trampoline. When the trampoline initializes the method's
170 // class, all its static methods code will be set to the instrumentation entry point.
171 // For more details, see ClassLinker::FixupStaticTrampolines.
172 if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
173 if (entry_exit_stubs_installed_) {
174 #if defined(ART_USE_PORTABLE_COMPILER)
175 new_portable_code = GetPortableToInterpreterBridge();
176 #endif
177 new_quick_code = GetQuickInstrumentationEntryPoint();
178 } else {
179 #if defined(ART_USE_PORTABLE_COMPILER)
180 new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
181 #endif
182 new_quick_code = class_linker->GetQuickOatCodeFor(method);
183 DCHECK(new_quick_code != class_linker->GetQuickToInterpreterBridgeTrampoline());
184 }
185 } else {
186 #if defined(ART_USE_PORTABLE_COMPILER)
187 new_portable_code = class_linker->GetPortableResolutionTrampoline();
188 #endif
189 new_quick_code = class_linker->GetQuickResolutionTrampoline();
190 }
191 }
192 }
193 UpdateEntrypoints(method, new_quick_code, new_portable_code, have_portable_code);
194 }
195
196 // Places the instrumentation exit pc as the return PC for every quick frame. This also allows
197 // deoptimization of quick frames to interpreter frames.
198 // Since we may already have done this previously, we need to push new instrumentation frame before
199 // existing instrumentation frames.
InstrumentationInstallStack(Thread * thread,void * arg)200 static void InstrumentationInstallStack(Thread* thread, void* arg)
201 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
202 struct InstallStackVisitor : public StackVisitor {
203 InstallStackVisitor(Thread* thread, Context* context, uintptr_t instrumentation_exit_pc)
204 : StackVisitor(thread, context), instrumentation_stack_(thread->GetInstrumentationStack()),
205 instrumentation_exit_pc_(instrumentation_exit_pc),
206 reached_existing_instrumentation_frames_(false), instrumentation_stack_depth_(0),
207 last_return_pc_(0) {
208 }
209
210 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
211 mirror::ArtMethod* m = GetMethod();
212 if (m == NULL) {
213 if (kVerboseInstrumentation) {
214 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
215 }
216 last_return_pc_ = 0;
217 return true; // Ignore upcalls.
218 }
219 if (GetCurrentQuickFrame() == NULL) {
220 bool interpreter_frame = !m->IsPortableCompiled();
221 InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, 0, GetFrameId(),
222 interpreter_frame);
223 if (kVerboseInstrumentation) {
224 LOG(INFO) << "Pushing shadow frame " << instrumentation_frame.Dump();
225 }
226 shadow_stack_.push_back(instrumentation_frame);
227 return true; // Continue.
228 }
229 uintptr_t return_pc = GetReturnPc();
230 if (m->IsRuntimeMethod()) {
231 if (return_pc == instrumentation_exit_pc_) {
232 if (kVerboseInstrumentation) {
233 LOG(INFO) << " Handling quick to interpreter transition. Frame " << GetFrameId();
234 }
235 CHECK_LT(instrumentation_stack_depth_, instrumentation_stack_->size());
236 const InstrumentationStackFrame& frame =
237 instrumentation_stack_->at(instrumentation_stack_depth_);
238 CHECK(frame.interpreter_entry_);
239 // This is an interpreter frame so method enter event must have been reported. However we
240 // need to push a DEX pc into the dex_pcs_ list to match size of instrumentation stack.
241 // Since we won't report method entry here, we can safely push any DEX pc.
242 dex_pcs_.push_back(0);
243 last_return_pc_ = frame.return_pc_;
244 ++instrumentation_stack_depth_;
245 return true;
246 } else {
247 if (kVerboseInstrumentation) {
248 LOG(INFO) << " Skipping runtime method. Frame " << GetFrameId();
249 }
250 last_return_pc_ = GetReturnPc();
251 return true; // Ignore unresolved methods since they will be instrumented after resolution.
252 }
253 }
254 if (kVerboseInstrumentation) {
255 LOG(INFO) << " Installing exit stub in " << DescribeLocation();
256 }
257 if (return_pc == instrumentation_exit_pc_) {
258 // We've reached a frame which has already been installed with instrumentation exit stub.
259 // We should have already installed instrumentation on previous frames.
260 reached_existing_instrumentation_frames_ = true;
261
262 CHECK_LT(instrumentation_stack_depth_, instrumentation_stack_->size());
263 const InstrumentationStackFrame& frame =
264 instrumentation_stack_->at(instrumentation_stack_depth_);
265 CHECK_EQ(m, frame.method_) << "Expected " << PrettyMethod(m)
266 << ", Found " << PrettyMethod(frame.method_);
267 return_pc = frame.return_pc_;
268 if (kVerboseInstrumentation) {
269 LOG(INFO) << "Ignoring already instrumented " << frame.Dump();
270 }
271 } else {
272 CHECK_NE(return_pc, 0U);
273 CHECK(!reached_existing_instrumentation_frames_);
274 InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, return_pc, GetFrameId(),
275 false);
276 if (kVerboseInstrumentation) {
277 LOG(INFO) << "Pushing frame " << instrumentation_frame.Dump();
278 }
279
280 // Insert frame at the right position so we do not corrupt the instrumentation stack.
281 // Instrumentation stack frames are in descending frame id order.
282 auto it = instrumentation_stack_->begin();
283 for (auto end = instrumentation_stack_->end(); it != end; ++it) {
284 const InstrumentationStackFrame& current = *it;
285 if (instrumentation_frame.frame_id_ >= current.frame_id_) {
286 break;
287 }
288 }
289 instrumentation_stack_->insert(it, instrumentation_frame);
290 SetReturnPc(instrumentation_exit_pc_);
291 }
292 dex_pcs_.push_back(m->ToDexPc(last_return_pc_));
293 last_return_pc_ = return_pc;
294 ++instrumentation_stack_depth_;
295 return true; // Continue.
296 }
297 std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
298 std::vector<InstrumentationStackFrame> shadow_stack_;
299 std::vector<uint32_t> dex_pcs_;
300 const uintptr_t instrumentation_exit_pc_;
301 bool reached_existing_instrumentation_frames_;
302 size_t instrumentation_stack_depth_;
303 uintptr_t last_return_pc_;
304 };
305 if (kVerboseInstrumentation) {
306 std::string thread_name;
307 thread->GetThreadName(thread_name);
308 LOG(INFO) << "Installing exit stubs in " << thread_name;
309 }
310
311 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
312 std::unique_ptr<Context> context(Context::Create());
313 uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
314 InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
315 visitor.WalkStack(true);
316 CHECK_EQ(visitor.dex_pcs_.size(), thread->GetInstrumentationStack()->size());
317
318 if (instrumentation->ShouldNotifyMethodEnterExitEvents()) {
319 // Create method enter events for all methods currently on the thread's stack. We only do this
320 // if no debugger is attached to prevent from posting events twice.
321 auto ssi = visitor.shadow_stack_.rbegin();
322 for (auto isi = thread->GetInstrumentationStack()->rbegin(),
323 end = thread->GetInstrumentationStack()->rend(); isi != end; ++isi) {
324 while (ssi != visitor.shadow_stack_.rend() && (*ssi).frame_id_ < (*isi).frame_id_) {
325 instrumentation->MethodEnterEvent(thread, (*ssi).this_object_, (*ssi).method_, 0);
326 ++ssi;
327 }
328 uint32_t dex_pc = visitor.dex_pcs_.back();
329 visitor.dex_pcs_.pop_back();
330 if (!isi->interpreter_entry_) {
331 instrumentation->MethodEnterEvent(thread, (*isi).this_object_, (*isi).method_, dex_pc);
332 }
333 }
334 }
335 thread->VerifyStack();
336 }
337
338 // Removes the instrumentation exit pc as the return PC for every quick frame.
InstrumentationRestoreStack(Thread * thread,void * arg)339 static void InstrumentationRestoreStack(Thread* thread, void* arg)
340 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
341 struct RestoreStackVisitor : public StackVisitor {
342 RestoreStackVisitor(Thread* thread, uintptr_t instrumentation_exit_pc,
343 Instrumentation* instrumentation)
344 : StackVisitor(thread, NULL), thread_(thread),
345 instrumentation_exit_pc_(instrumentation_exit_pc),
346 instrumentation_(instrumentation),
347 instrumentation_stack_(thread->GetInstrumentationStack()),
348 frames_removed_(0) {}
349
350 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
351 if (instrumentation_stack_->size() == 0) {
352 return false; // Stop.
353 }
354 mirror::ArtMethod* m = GetMethod();
355 if (GetCurrentQuickFrame() == NULL) {
356 if (kVerboseInstrumentation) {
357 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId()
358 << " Method=" << PrettyMethod(m);
359 }
360 return true; // Ignore shadow frames.
361 }
362 if (m == NULL) {
363 if (kVerboseInstrumentation) {
364 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
365 }
366 return true; // Ignore upcalls.
367 }
368 bool removed_stub = false;
369 // TODO: make this search more efficient?
370 const size_t frameId = GetFrameId();
371 for (const InstrumentationStackFrame& instrumentation_frame : *instrumentation_stack_) {
372 if (instrumentation_frame.frame_id_ == frameId) {
373 if (kVerboseInstrumentation) {
374 LOG(INFO) << " Removing exit stub in " << DescribeLocation();
375 }
376 if (instrumentation_frame.interpreter_entry_) {
377 CHECK(m == Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
378 } else {
379 CHECK(m == instrumentation_frame.method_) << PrettyMethod(m);
380 }
381 SetReturnPc(instrumentation_frame.return_pc_);
382 if (instrumentation_->ShouldNotifyMethodEnterExitEvents()) {
383 // Create the method exit events. As the methods didn't really exit the result is 0.
384 // We only do this if no debugger is attached to prevent from posting events twice.
385 instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m,
386 GetDexPc(), JValue());
387 }
388 frames_removed_++;
389 removed_stub = true;
390 break;
391 }
392 }
393 if (!removed_stub) {
394 if (kVerboseInstrumentation) {
395 LOG(INFO) << " No exit stub in " << DescribeLocation();
396 }
397 }
398 return true; // Continue.
399 }
400 Thread* const thread_;
401 const uintptr_t instrumentation_exit_pc_;
402 Instrumentation* const instrumentation_;
403 std::deque<instrumentation::InstrumentationStackFrame>* const instrumentation_stack_;
404 size_t frames_removed_;
405 };
406 if (kVerboseInstrumentation) {
407 std::string thread_name;
408 thread->GetThreadName(thread_name);
409 LOG(INFO) << "Removing exit stubs in " << thread_name;
410 }
411 std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
412 if (stack->size() > 0) {
413 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
414 uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
415 RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
416 visitor.WalkStack(true);
417 CHECK_EQ(visitor.frames_removed_, stack->size());
418 while (stack->size() > 0) {
419 stack->pop_front();
420 }
421 }
422 }
423
AddListener(InstrumentationListener * listener,uint32_t events)424 void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
425 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
426 if ((events & kMethodEntered) != 0) {
427 method_entry_listeners_.push_back(listener);
428 have_method_entry_listeners_ = true;
429 }
430 if ((events & kMethodExited) != 0) {
431 method_exit_listeners_.push_back(listener);
432 have_method_exit_listeners_ = true;
433 }
434 if ((events & kMethodUnwind) != 0) {
435 method_unwind_listeners_.push_back(listener);
436 have_method_unwind_listeners_ = true;
437 }
438 if ((events & kDexPcMoved) != 0) {
439 std::list<InstrumentationListener*>* modified;
440 if (have_dex_pc_listeners_) {
441 modified = new std::list<InstrumentationListener*>(*dex_pc_listeners_.get());
442 } else {
443 modified = new std::list<InstrumentationListener*>();
444 }
445 modified->push_back(listener);
446 dex_pc_listeners_.reset(modified);
447 have_dex_pc_listeners_ = true;
448 }
449 if ((events & kFieldRead) != 0) {
450 std::list<InstrumentationListener*>* modified;
451 if (have_field_read_listeners_) {
452 modified = new std::list<InstrumentationListener*>(*field_read_listeners_.get());
453 } else {
454 modified = new std::list<InstrumentationListener*>();
455 }
456 modified->push_back(listener);
457 field_read_listeners_.reset(modified);
458 have_field_read_listeners_ = true;
459 }
460 if ((events & kFieldWritten) != 0) {
461 std::list<InstrumentationListener*>* modified;
462 if (have_field_write_listeners_) {
463 modified = new std::list<InstrumentationListener*>(*field_write_listeners_.get());
464 } else {
465 modified = new std::list<InstrumentationListener*>();
466 }
467 modified->push_back(listener);
468 field_write_listeners_.reset(modified);
469 have_field_write_listeners_ = true;
470 }
471 if ((events & kExceptionCaught) != 0) {
472 std::list<InstrumentationListener*>* modified;
473 if (have_exception_caught_listeners_) {
474 modified = new std::list<InstrumentationListener*>(*exception_caught_listeners_.get());
475 } else {
476 modified = new std::list<InstrumentationListener*>();
477 }
478 modified->push_back(listener);
479 exception_caught_listeners_.reset(modified);
480 have_exception_caught_listeners_ = true;
481 }
482 UpdateInterpreterHandlerTable();
483 }
484
RemoveListener(InstrumentationListener * listener,uint32_t events)485 void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
486 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
487
488 if ((events & kMethodEntered) != 0) {
489 if (have_method_entry_listeners_) {
490 method_entry_listeners_.remove(listener);
491 have_method_entry_listeners_ = !method_entry_listeners_.empty();
492 }
493 }
494 if ((events & kMethodExited) != 0) {
495 if (have_method_exit_listeners_) {
496 method_exit_listeners_.remove(listener);
497 have_method_exit_listeners_ = !method_exit_listeners_.empty();
498 }
499 }
500 if ((events & kMethodUnwind) != 0) {
501 if (have_method_unwind_listeners_) {
502 method_unwind_listeners_.remove(listener);
503 have_method_unwind_listeners_ = !method_unwind_listeners_.empty();
504 }
505 }
506 if ((events & kDexPcMoved) != 0) {
507 if (have_dex_pc_listeners_) {
508 std::list<InstrumentationListener*>* modified =
509 new std::list<InstrumentationListener*>(*dex_pc_listeners_.get());
510 modified->remove(listener);
511 have_dex_pc_listeners_ = !modified->empty();
512 if (have_dex_pc_listeners_) {
513 dex_pc_listeners_.reset(modified);
514 } else {
515 dex_pc_listeners_.reset();
516 delete modified;
517 }
518 }
519 }
520 if ((events & kFieldRead) != 0) {
521 if (have_field_read_listeners_) {
522 std::list<InstrumentationListener*>* modified =
523 new std::list<InstrumentationListener*>(*field_read_listeners_.get());
524 modified->remove(listener);
525 have_field_read_listeners_ = !modified->empty();
526 if (have_field_read_listeners_) {
527 field_read_listeners_.reset(modified);
528 } else {
529 field_read_listeners_.reset();
530 delete modified;
531 }
532 }
533 }
534 if ((events & kFieldWritten) != 0) {
535 if (have_field_write_listeners_) {
536 std::list<InstrumentationListener*>* modified =
537 new std::list<InstrumentationListener*>(*field_write_listeners_.get());
538 modified->remove(listener);
539 have_field_write_listeners_ = !modified->empty();
540 if (have_field_write_listeners_) {
541 field_write_listeners_.reset(modified);
542 } else {
543 field_write_listeners_.reset();
544 delete modified;
545 }
546 }
547 }
548 if ((events & kExceptionCaught) != 0) {
549 if (have_exception_caught_listeners_) {
550 std::list<InstrumentationListener*>* modified =
551 new std::list<InstrumentationListener*>(*exception_caught_listeners_.get());
552 modified->remove(listener);
553 have_exception_caught_listeners_ = !modified->empty();
554 if (have_exception_caught_listeners_) {
555 exception_caught_listeners_.reset(modified);
556 } else {
557 exception_caught_listeners_.reset();
558 delete modified;
559 }
560 }
561 }
562 UpdateInterpreterHandlerTable();
563 }
564
ConfigureStubs(bool require_entry_exit_stubs,bool require_interpreter)565 void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter) {
566 interpret_only_ = require_interpreter || forced_interpret_only_;
567 // Compute what level of instrumentation is required and compare to current.
568 int desired_level, current_level;
569 if (require_interpreter) {
570 desired_level = 2;
571 } else if (require_entry_exit_stubs) {
572 desired_level = 1;
573 } else {
574 desired_level = 0;
575 }
576 if (interpreter_stubs_installed_) {
577 current_level = 2;
578 } else if (entry_exit_stubs_installed_) {
579 current_level = 1;
580 } else {
581 current_level = 0;
582 }
583 if (desired_level == current_level) {
584 // We're already set.
585 return;
586 }
587 Thread* const self = Thread::Current();
588 Runtime* runtime = Runtime::Current();
589 Locks::thread_list_lock_->AssertNotHeld(self);
590 if (desired_level > 0) {
591 if (require_interpreter) {
592 interpreter_stubs_installed_ = true;
593 } else {
594 CHECK(require_entry_exit_stubs);
595 entry_exit_stubs_installed_ = true;
596 }
597 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
598 instrumentation_stubs_installed_ = true;
599 MutexLock mu(self, *Locks::thread_list_lock_);
600 runtime->GetThreadList()->ForEach(InstrumentationInstallStack, this);
601 } else {
602 interpreter_stubs_installed_ = false;
603 entry_exit_stubs_installed_ = false;
604 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
605 // Restore stack only if there is no method currently deoptimized.
606 bool empty;
607 {
608 ReaderMutexLock mu(self, deoptimized_methods_lock_);
609 empty = IsDeoptimizedMethodsEmpty(); // Avoid lock violation.
610 }
611 if (empty) {
612 instrumentation_stubs_installed_ = false;
613 MutexLock mu(self, *Locks::thread_list_lock_);
614 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
615 }
616 }
617 }
618
ResetQuickAllocEntryPointsForThread(Thread * thread,void * arg)619 static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
620 thread->ResetQuickAllocEntryPointsForThread();
621 }
622
SetEntrypointsInstrumented(bool instrumented)623 void Instrumentation::SetEntrypointsInstrumented(bool instrumented) {
624 Thread* self = Thread::Current();
625 Runtime* runtime = Runtime::Current();
626 ThreadList* tl = runtime->GetThreadList();
627 Locks::mutator_lock_->AssertNotHeld(self);
628 Locks::instrument_entrypoints_lock_->AssertHeld(self);
629 if (runtime->IsStarted()) {
630 tl->SuspendAll();
631 }
632 {
633 MutexLock mu(self, *Locks::runtime_shutdown_lock_);
634 SetQuickAllocEntryPointsInstrumented(instrumented);
635 ResetQuickAllocEntryPoints();
636 }
637 if (runtime->IsStarted()) {
638 tl->ResumeAll();
639 }
640 }
641
InstrumentQuickAllocEntryPoints()642 void Instrumentation::InstrumentQuickAllocEntryPoints() {
643 MutexLock mu(Thread::Current(), *Locks::instrument_entrypoints_lock_);
644 InstrumentQuickAllocEntryPointsLocked();
645 }
646
UninstrumentQuickAllocEntryPoints()647 void Instrumentation::UninstrumentQuickAllocEntryPoints() {
648 MutexLock mu(Thread::Current(), *Locks::instrument_entrypoints_lock_);
649 UninstrumentQuickAllocEntryPointsLocked();
650 }
651
InstrumentQuickAllocEntryPointsLocked()652 void Instrumentation::InstrumentQuickAllocEntryPointsLocked() {
653 Locks::instrument_entrypoints_lock_->AssertHeld(Thread::Current());
654 if (quick_alloc_entry_points_instrumentation_counter_ == 0) {
655 SetEntrypointsInstrumented(true);
656 }
657 ++quick_alloc_entry_points_instrumentation_counter_;
658 LOG(INFO) << "Counter: " << quick_alloc_entry_points_instrumentation_counter_;
659 }
660
UninstrumentQuickAllocEntryPointsLocked()661 void Instrumentation::UninstrumentQuickAllocEntryPointsLocked() {
662 Locks::instrument_entrypoints_lock_->AssertHeld(Thread::Current());
663 CHECK_GT(quick_alloc_entry_points_instrumentation_counter_, 0U);
664 --quick_alloc_entry_points_instrumentation_counter_;
665 if (quick_alloc_entry_points_instrumentation_counter_ == 0) {
666 SetEntrypointsInstrumented(false);
667 }
668 LOG(INFO) << "Counter: " << quick_alloc_entry_points_instrumentation_counter_;
669 }
670
ResetQuickAllocEntryPoints()671 void Instrumentation::ResetQuickAllocEntryPoints() {
672 Runtime* runtime = Runtime::Current();
673 if (runtime->IsStarted()) {
674 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
675 runtime->GetThreadList()->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
676 }
677 }
678
UpdateMethodsCode(mirror::ArtMethod * method,const void * quick_code,const void * portable_code,bool have_portable_code)679 void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code,
680 const void* portable_code, bool have_portable_code) {
681 const void* new_portable_code;
682 const void* new_quick_code;
683 bool new_have_portable_code;
684 if (LIKELY(!instrumentation_stubs_installed_)) {
685 new_portable_code = portable_code;
686 new_quick_code = quick_code;
687 new_have_portable_code = have_portable_code;
688 } else {
689 if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) {
690 #if defined(ART_USE_PORTABLE_COMPILER)
691 new_portable_code = GetPortableToInterpreterBridge();
692 #else
693 new_portable_code = portable_code;
694 #endif
695 new_quick_code = GetQuickToInterpreterBridge();
696 new_have_portable_code = false;
697 } else {
698 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
699 if (quick_code == class_linker->GetQuickResolutionTrampoline() ||
700 quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
701 quick_code == GetQuickToInterpreterBridge()) {
702 #if defined(ART_USE_PORTABLE_COMPILER)
703 DCHECK((portable_code == class_linker->GetPortableResolutionTrampoline()) ||
704 (portable_code == GetPortableToInterpreterBridge()));
705 #endif
706 new_portable_code = portable_code;
707 new_quick_code = quick_code;
708 new_have_portable_code = have_portable_code;
709 } else if (entry_exit_stubs_installed_) {
710 new_quick_code = GetQuickInstrumentationEntryPoint();
711 #if defined(ART_USE_PORTABLE_COMPILER)
712 new_portable_code = GetPortableToInterpreterBridge();
713 #else
714 new_portable_code = portable_code;
715 #endif
716 new_have_portable_code = false;
717 } else {
718 new_portable_code = portable_code;
719 new_quick_code = quick_code;
720 new_have_portable_code = have_portable_code;
721 }
722 }
723 }
724 UpdateEntrypoints(method, new_quick_code, new_portable_code, new_have_portable_code);
725 }
726
AddDeoptimizedMethod(mirror::ArtMethod * method)727 bool Instrumentation::AddDeoptimizedMethod(mirror::ArtMethod* method) {
728 // Note that the insert() below isn't read barrier-aware. So, this
729 // FindDeoptimizedMethod() call is necessary or else we would end up
730 // storing the same method twice in the map (the from-space and the
731 // to-space ones).
732 if (FindDeoptimizedMethod(method)) {
733 // Already in the map. Return.
734 return false;
735 }
736 // Not found. Add it.
737 int32_t hash_code = method->IdentityHashCode();
738 deoptimized_methods_.insert(std::make_pair(hash_code, GcRoot<mirror::ArtMethod>(method)));
739 return true;
740 }
741
FindDeoptimizedMethod(mirror::ArtMethod * method)742 bool Instrumentation::FindDeoptimizedMethod(mirror::ArtMethod* method) {
743 int32_t hash_code = method->IdentityHashCode();
744 auto range = deoptimized_methods_.equal_range(hash_code);
745 for (auto it = range.first; it != range.second; ++it) {
746 mirror::ArtMethod* m = it->second.Read();
747 if (m == method) {
748 // Found.
749 return true;
750 }
751 }
752 // Not found.
753 return false;
754 }
755
BeginDeoptimizedMethod()756 mirror::ArtMethod* Instrumentation::BeginDeoptimizedMethod() {
757 auto it = deoptimized_methods_.begin();
758 if (it == deoptimized_methods_.end()) {
759 // Empty.
760 return nullptr;
761 }
762 return it->second.Read();
763 }
764
RemoveDeoptimizedMethod(mirror::ArtMethod * method)765 bool Instrumentation::RemoveDeoptimizedMethod(mirror::ArtMethod* method) {
766 int32_t hash_code = method->IdentityHashCode();
767 auto range = deoptimized_methods_.equal_range(hash_code);
768 for (auto it = range.first; it != range.second; ++it) {
769 mirror::ArtMethod* m = it->second.Read();
770 if (m == method) {
771 // Found. Erase and return.
772 deoptimized_methods_.erase(it);
773 return true;
774 }
775 }
776 // Not found.
777 return false;
778 }
779
IsDeoptimizedMethodsEmpty() const780 bool Instrumentation::IsDeoptimizedMethodsEmpty() const {
781 return deoptimized_methods_.empty();
782 }
783
Deoptimize(mirror::ArtMethod * method)784 void Instrumentation::Deoptimize(mirror::ArtMethod* method) {
785 CHECK(!method->IsNative());
786 CHECK(!method->IsProxyMethod());
787 CHECK(!method->IsAbstract());
788
789 Thread* self = Thread::Current();
790 {
791 WriterMutexLock mu(self, deoptimized_methods_lock_);
792 bool has_not_been_deoptimized = AddDeoptimizedMethod(method);
793 CHECK(has_not_been_deoptimized) << "Method " << PrettyMethod(method)
794 << " is already deoptimized";
795 }
796 if (!interpreter_stubs_installed_) {
797 UpdateEntrypoints(method, GetQuickInstrumentationEntryPoint(),
798 #if defined(ART_USE_PORTABLE_COMPILER)
799 GetPortableToInterpreterBridge(),
800 #else
801 nullptr,
802 #endif
803 false);
804
805 // Install instrumentation exit stub and instrumentation frames. We may already have installed
806 // these previously so it will only cover the newly created frames.
807 instrumentation_stubs_installed_ = true;
808 MutexLock mu(self, *Locks::thread_list_lock_);
809 Runtime::Current()->GetThreadList()->ForEach(InstrumentationInstallStack, this);
810 }
811 }
812
Undeoptimize(mirror::ArtMethod * method)813 void Instrumentation::Undeoptimize(mirror::ArtMethod* method) {
814 CHECK(!method->IsNative());
815 CHECK(!method->IsProxyMethod());
816 CHECK(!method->IsAbstract());
817
818 Thread* self = Thread::Current();
819 bool empty;
820 {
821 WriterMutexLock mu(self, deoptimized_methods_lock_);
822 bool found_and_erased = RemoveDeoptimizedMethod(method);
823 CHECK(found_and_erased) << "Method " << PrettyMethod(method)
824 << " is not deoptimized";
825 empty = IsDeoptimizedMethodsEmpty();
826 }
827
828 // Restore code and possibly stack only if we did not deoptimize everything.
829 if (!interpreter_stubs_installed_) {
830 // Restore its code or resolution trampoline.
831 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
832 if (method->IsStatic() && !method->IsConstructor() &&
833 !method->GetDeclaringClass()->IsInitialized()) {
834 // TODO: we're updating to entrypoints in the image here, we can avoid the trampoline.
835 UpdateEntrypoints(method, class_linker->GetQuickResolutionTrampoline(),
836 #if defined(ART_USE_PORTABLE_COMPILER)
837 class_linker->GetPortableResolutionTrampoline(),
838 #else
839 nullptr,
840 #endif
841 false);
842 } else {
843 bool have_portable_code = false;
844 const void* quick_code = class_linker->GetQuickOatCodeFor(method);
845 #if defined(ART_USE_PORTABLE_COMPILER)
846 const void* portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
847 #else
848 const void* portable_code = nullptr;
849 #endif
850 UpdateEntrypoints(method, quick_code, portable_code, have_portable_code);
851 }
852
853 // If there is no deoptimized method left, we can restore the stack of each thread.
854 if (empty) {
855 MutexLock mu(self, *Locks::thread_list_lock_);
856 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
857 instrumentation_stubs_installed_ = false;
858 }
859 }
860 }
861
IsDeoptimized(mirror::ArtMethod * method)862 bool Instrumentation::IsDeoptimized(mirror::ArtMethod* method) {
863 DCHECK(method != nullptr);
864 ReaderMutexLock mu(Thread::Current(), deoptimized_methods_lock_);
865 return FindDeoptimizedMethod(method);
866 }
867
EnableDeoptimization()868 void Instrumentation::EnableDeoptimization() {
869 ReaderMutexLock mu(Thread::Current(), deoptimized_methods_lock_);
870 CHECK(IsDeoptimizedMethodsEmpty());
871 CHECK_EQ(deoptimization_enabled_, false);
872 deoptimization_enabled_ = true;
873 }
874
DisableDeoptimization()875 void Instrumentation::DisableDeoptimization() {
876 CHECK_EQ(deoptimization_enabled_, true);
877 // If we deoptimized everything, undo it.
878 if (interpreter_stubs_installed_) {
879 UndeoptimizeEverything();
880 }
881 // Undeoptimized selected methods.
882 while (true) {
883 mirror::ArtMethod* method;
884 {
885 ReaderMutexLock mu(Thread::Current(), deoptimized_methods_lock_);
886 if (IsDeoptimizedMethodsEmpty()) {
887 break;
888 }
889 method = BeginDeoptimizedMethod();
890 CHECK(method != nullptr);
891 }
892 Undeoptimize(method);
893 }
894 deoptimization_enabled_ = false;
895 }
896
897 // Indicates if instrumentation should notify method enter/exit events to the listeners.
ShouldNotifyMethodEnterExitEvents() const898 bool Instrumentation::ShouldNotifyMethodEnterExitEvents() const {
899 return !deoptimization_enabled_ && !interpreter_stubs_installed_;
900 }
901
DeoptimizeEverything()902 void Instrumentation::DeoptimizeEverything() {
903 CHECK(!interpreter_stubs_installed_);
904 ConfigureStubs(false, true);
905 }
906
UndeoptimizeEverything()907 void Instrumentation::UndeoptimizeEverything() {
908 CHECK(interpreter_stubs_installed_);
909 ConfigureStubs(false, false);
910 }
911
EnableMethodTracing()912 void Instrumentation::EnableMethodTracing() {
913 bool require_interpreter = kDeoptimizeForAccurateMethodEntryExitListeners;
914 ConfigureStubs(!require_interpreter, require_interpreter);
915 }
916
DisableMethodTracing()917 void Instrumentation::DisableMethodTracing() {
918 ConfigureStubs(false, false);
919 }
920
GetQuickCodeFor(mirror::ArtMethod * method,size_t pointer_size) const921 const void* Instrumentation::GetQuickCodeFor(mirror::ArtMethod* method, size_t pointer_size) const {
922 Runtime* runtime = Runtime::Current();
923 if (LIKELY(!instrumentation_stubs_installed_)) {
924 const void* code = method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
925 DCHECK(code != nullptr);
926 ClassLinker* class_linker = runtime->GetClassLinker();
927 if (LIKELY(code != class_linker->GetQuickResolutionTrampoline()) &&
928 LIKELY(code != class_linker->GetQuickToInterpreterBridgeTrampoline()) &&
929 LIKELY(code != GetQuickToInterpreterBridge())) {
930 return code;
931 }
932 }
933 return runtime->GetClassLinker()->GetQuickOatCodeFor(method);
934 }
935
MethodEnterEventImpl(Thread * thread,mirror::Object * this_object,mirror::ArtMethod * method,uint32_t dex_pc) const936 void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
937 mirror::ArtMethod* method,
938 uint32_t dex_pc) const {
939 auto it = method_entry_listeners_.begin();
940 bool is_end = (it == method_entry_listeners_.end());
941 // Implemented this way to prevent problems caused by modification of the list while iterating.
942 while (!is_end) {
943 InstrumentationListener* cur = *it;
944 ++it;
945 is_end = (it == method_entry_listeners_.end());
946 cur->MethodEntered(thread, this_object, method, dex_pc);
947 }
948 }
949
MethodExitEventImpl(Thread * thread,mirror::Object * this_object,mirror::ArtMethod * method,uint32_t dex_pc,const JValue & return_value) const950 void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
951 mirror::ArtMethod* method,
952 uint32_t dex_pc, const JValue& return_value) const {
953 auto it = method_exit_listeners_.begin();
954 bool is_end = (it == method_exit_listeners_.end());
955 // Implemented this way to prevent problems caused by modification of the list while iterating.
956 while (!is_end) {
957 InstrumentationListener* cur = *it;
958 ++it;
959 is_end = (it == method_exit_listeners_.end());
960 cur->MethodExited(thread, this_object, method, dex_pc, return_value);
961 }
962 }
963
MethodUnwindEvent(Thread * thread,mirror::Object * this_object,mirror::ArtMethod * method,uint32_t dex_pc) const964 void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
965 mirror::ArtMethod* method,
966 uint32_t dex_pc) const {
967 if (have_method_unwind_listeners_) {
968 for (InstrumentationListener* listener : method_unwind_listeners_) {
969 listener->MethodUnwind(thread, this_object, method, dex_pc);
970 }
971 }
972 }
973
DexPcMovedEventImpl(Thread * thread,mirror::Object * this_object,mirror::ArtMethod * method,uint32_t dex_pc) const974 void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
975 mirror::ArtMethod* method,
976 uint32_t dex_pc) const {
977 if (HasDexPcListeners()) {
978 std::shared_ptr<std::list<InstrumentationListener*>> original(dex_pc_listeners_);
979 for (InstrumentationListener* listener : *original.get()) {
980 listener->DexPcMoved(thread, this_object, method, dex_pc);
981 }
982 }
983 }
984
FieldReadEventImpl(Thread * thread,mirror::Object * this_object,mirror::ArtMethod * method,uint32_t dex_pc,mirror::ArtField * field) const985 void Instrumentation::FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
986 mirror::ArtMethod* method, uint32_t dex_pc,
987 mirror::ArtField* field) const {
988 if (HasFieldReadListeners()) {
989 std::shared_ptr<std::list<InstrumentationListener*>> original(field_read_listeners_);
990 for (InstrumentationListener* listener : *original.get()) {
991 listener->FieldRead(thread, this_object, method, dex_pc, field);
992 }
993 }
994 }
995
FieldWriteEventImpl(Thread * thread,mirror::Object * this_object,mirror::ArtMethod * method,uint32_t dex_pc,mirror::ArtField * field,const JValue & field_value) const996 void Instrumentation::FieldWriteEventImpl(Thread* thread, mirror::Object* this_object,
997 mirror::ArtMethod* method, uint32_t dex_pc,
998 mirror::ArtField* field, const JValue& field_value) const {
999 if (HasFieldWriteListeners()) {
1000 std::shared_ptr<std::list<InstrumentationListener*>> original(field_write_listeners_);
1001 for (InstrumentationListener* listener : *original.get()) {
1002 listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value);
1003 }
1004 }
1005 }
1006
ExceptionCaughtEvent(Thread * thread,const ThrowLocation & throw_location,mirror::ArtMethod * catch_method,uint32_t catch_dex_pc,mirror::Throwable * exception_object) const1007 void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
1008 mirror::ArtMethod* catch_method,
1009 uint32_t catch_dex_pc,
1010 mirror::Throwable* exception_object) const {
1011 if (HasExceptionCaughtListeners()) {
1012 DCHECK_EQ(thread->GetException(nullptr), exception_object);
1013 bool is_exception_reported = thread->IsExceptionReportedToInstrumentation();
1014 thread->ClearException();
1015 std::shared_ptr<std::list<InstrumentationListener*>> original(exception_caught_listeners_);
1016 for (InstrumentationListener* listener : *original.get()) {
1017 listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc,
1018 exception_object);
1019 }
1020 thread->SetException(throw_location, exception_object);
1021 thread->SetExceptionReportedToInstrumentation(is_exception_reported);
1022 }
1023 }
1024
CheckStackDepth(Thread * self,const InstrumentationStackFrame & instrumentation_frame,int delta)1025 static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
1026 int delta)
1027 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
1028 size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
1029 if (frame_id != instrumentation_frame.frame_id_) {
1030 LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
1031 << instrumentation_frame.frame_id_;
1032 StackVisitor::DescribeStack(self);
1033 CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
1034 }
1035 }
1036
PushInstrumentationStackFrame(Thread * self,mirror::Object * this_object,mirror::ArtMethod * method,uintptr_t lr,bool interpreter_entry)1037 void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
1038 mirror::ArtMethod* method,
1039 uintptr_t lr, bool interpreter_entry) {
1040 // We have a callee-save frame meaning this value is guaranteed to never be 0.
1041 size_t frame_id = StackVisitor::ComputeNumFrames(self);
1042 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
1043 if (kVerboseInstrumentation) {
1044 LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << reinterpret_cast<void*>(lr);
1045 }
1046 instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
1047 frame_id, interpreter_entry);
1048 stack->push_front(instrumentation_frame);
1049
1050 if (!interpreter_entry) {
1051 MethodEnterEvent(self, this_object, method, 0);
1052 }
1053 }
1054
PopInstrumentationStackFrame(Thread * self,uintptr_t * return_pc,uint64_t gpr_result,uint64_t fpr_result)1055 TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
1056 uint64_t gpr_result,
1057 uint64_t fpr_result) {
1058 // Do the pop.
1059 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
1060 CHECK_GT(stack->size(), 0U);
1061 InstrumentationStackFrame instrumentation_frame = stack->front();
1062 stack->pop_front();
1063
1064 // Set return PC and check the sanity of the stack.
1065 *return_pc = instrumentation_frame.return_pc_;
1066 CheckStackDepth(self, instrumentation_frame, 0);
1067
1068 mirror::ArtMethod* method = instrumentation_frame.method_;
1069 uint32_t length;
1070 char return_shorty = method->GetShorty(&length)[0];
1071 JValue return_value;
1072 if (return_shorty == 'V') {
1073 return_value.SetJ(0);
1074 } else if (return_shorty == 'F' || return_shorty == 'D') {
1075 return_value.SetJ(fpr_result);
1076 } else {
1077 return_value.SetJ(gpr_result);
1078 }
1079 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
1080 // return_pc.
1081 uint32_t dex_pc = DexFile::kDexNoIndex;
1082 mirror::Object* this_object = instrumentation_frame.this_object_;
1083 if (!instrumentation_frame.interpreter_entry_) {
1084 MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
1085 }
1086
1087 // Deoptimize if the caller needs to continue execution in the interpreter. Do nothing if we get
1088 // back to an upcall.
1089 NthCallerVisitor visitor(self, 1, true);
1090 visitor.WalkStack(true);
1091 bool deoptimize = (visitor.caller != nullptr) &&
1092 (interpreter_stubs_installed_ || IsDeoptimized(visitor.caller));
1093 if (deoptimize) {
1094 if (kVerboseInstrumentation) {
1095 LOG(INFO) << StringPrintf("Deoptimizing %s by returning from %s with result %#" PRIx64 " in ",
1096 PrettyMethod(visitor.caller).c_str(),
1097 PrettyMethod(method).c_str(),
1098 return_value.GetJ()) << *self;
1099 }
1100 self->SetDeoptimizationReturnValue(return_value);
1101 return GetTwoWordSuccessValue(*return_pc,
1102 reinterpret_cast<uintptr_t>(GetQuickDeoptimizationEntryPoint()));
1103 } else {
1104 if (kVerboseInstrumentation) {
1105 LOG(INFO) << "Returning from " << PrettyMethod(method)
1106 << " to PC " << reinterpret_cast<void*>(*return_pc);
1107 }
1108 return GetTwoWordSuccessValue(0, *return_pc);
1109 }
1110 }
1111
PopMethodForUnwind(Thread * self,bool is_deoptimization) const1112 void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
1113 // Do the pop.
1114 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
1115 CHECK_GT(stack->size(), 0U);
1116 InstrumentationStackFrame instrumentation_frame = stack->front();
1117 // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
1118 stack->pop_front();
1119
1120 mirror::ArtMethod* method = instrumentation_frame.method_;
1121 if (is_deoptimization) {
1122 if (kVerboseInstrumentation) {
1123 LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
1124 }
1125 } else {
1126 if (kVerboseInstrumentation) {
1127 LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
1128 }
1129
1130 // Notify listeners of method unwind.
1131 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
1132 // return_pc.
1133 uint32_t dex_pc = DexFile::kDexNoIndex;
1134 MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
1135 }
1136 }
1137
VisitRoots(RootCallback * callback,void * arg)1138 void Instrumentation::VisitRoots(RootCallback* callback, void* arg) {
1139 WriterMutexLock mu(Thread::Current(), deoptimized_methods_lock_);
1140 if (IsDeoptimizedMethodsEmpty()) {
1141 return;
1142 }
1143 for (auto pair : deoptimized_methods_) {
1144 pair.second.VisitRoot(callback, arg, RootInfo(kRootVMInternal));
1145 }
1146 }
1147
Dump() const1148 std::string InstrumentationStackFrame::Dump() const {
1149 std::ostringstream os;
1150 os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
1151 << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
1152 return os.str();
1153 }
1154
1155 } // namespace instrumentation
1156 } // namespace art
1157