blob: 710d9dd7b3ff4df13fbcb63e75b2e156dee38a2b [file] [log] [blame]
jeffhao725a9572012-11-13 18:20:12 -08001/*
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
Ian Rogers62d6c772013-02-27 08:32:07 -080021#include "atomic_integer.h"
Elliott Hughes76160052012-12-12 16:31:20 -080022#include "base/unix_file/fd_file.h"
jeffhao725a9572012-11-13 18:20:12 -080023#include "class_linker.h"
24#include "debugger.h"
Ian Rogers62d6c772013-02-27 08:32:07 -080025#include "dex_file-inl.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070026#include "mirror/art_method-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080027#include "mirror/class-inl.h"
28#include "mirror/dex_cache.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080029#include "mirror/object_array-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070030#include "mirror/object-inl.h"
Ian Rogers62d6c772013-02-27 08:32:07 -080031#include "nth_caller_visitor.h"
Ian Rogersc928de92013-02-27 14:30:44 -080032#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers166db042013-07-26 12:05:57 -070033#include "entrypoints/quick/quick_entrypoints.h"
jeffhao725a9572012-11-13 18:20:12 -080034#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"
jeffhao725a9572012-11-13 18:20:12 -080040
41namespace art {
Ian Rogersfa824272013-11-05 16:12:57 -080042
43extern void SetQuickAllocEntryPointsInstrumented(bool instrumented);
44
Ian Rogers62d6c772013-02-27 08:32:07 -080045namespace instrumentation {
jeffhao725a9572012-11-13 18:20:12 -080046
Sebastien Hertz5bfd5c92013-11-15 11:36:07 +010047const bool kVerboseInstrumentation = false;
48
Ian Rogers816432e2013-09-06 15:47:45 -070049// Do we want to deoptimize for method entry and exit listeners or just try to intercept
50// invocations? Deoptimization forces all code to run in the interpreter and considerably hurts the
51// application's performance.
Ian Rogers7b6da362013-09-11 09:29:40 -070052static constexpr bool kDeoptimizeForAccurateMethodEntryExitListeners = false;
Ian Rogers816432e2013-09-06 15:47:45 -070053
Ian Rogers62d6c772013-02-27 08:32:07 -080054static bool InstallStubsClassVisitor(mirror::Class* klass, void* arg)
jeffhao725a9572012-11-13 18:20:12 -080055 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -080056 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
57 return instrumentation->InstallStubsForClass(klass);
58}
59
60bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
61 bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
Sebastien Hertz5bfd5c92013-11-15 11:36:07 +010062 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogers62d6c772013-02-27 08:32:07 -080063 bool is_initialized = klass->IsInitialized();
jeffhao725a9572012-11-13 18:20:12 -080064 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
Brian Carlstromea46f952013-07-30 01:26:50 -070065 mirror::ArtMethod* method = klass->GetDirectMethod(i);
Jeff Hao02b10d62013-11-06 15:21:24 -080066 if (!method->IsAbstract() && !method->IsProxyMethod()) {
Ian Rogers62d6c772013-02-27 08:32:07 -080067 const void* new_code;
68 if (uninstall) {
Jeff Hao02b10d62013-11-06 15:21:24 -080069 if (forced_interpret_only_ && !method->IsNative()) {
Ian Rogers848871b2013-08-05 10:56:33 -070070 new_code = GetCompiledCodeToInterpreterBridge();
Jeff Hao65d15d92013-07-16 16:39:33 -070071 } else if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
Ian Rogers62d6c772013-02-27 08:32:07 -080072 new_code = class_linker->GetOatCodeFor(method);
73 } else {
Jeff Hao0aba0ba2013-06-03 14:49:28 -070074 new_code = GetResolutionTrampoline(class_linker);
Ian Rogers62d6c772013-02-27 08:32:07 -080075 }
76 } else { // !uninstall
77 if (!interpreter_stubs_installed_ || method->IsNative()) {
Sebastien Hertz5bfd5c92013-11-15 11:36:07 +010078 // Do not overwrite resolution trampoline. When the trampoline initializes the method's
79 // class, all its static methods' code will be set to the instrumentation entry point.
80 // For more details, see ClassLinker::FixupStaticTrampolines.
81 if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
82 new_code = GetQuickInstrumentationEntryPoint();
83 } else {
84 new_code = GetResolutionTrampoline(class_linker);
85 }
Ian Rogers62d6c772013-02-27 08:32:07 -080086 } else {
Ian Rogers848871b2013-08-05 10:56:33 -070087 new_code = GetCompiledCodeToInterpreterBridge();
Ian Rogers62d6c772013-02-27 08:32:07 -080088 }
89 }
Jeff Haoaa4a7932013-05-13 11:28:27 -070090 method->SetEntryPointFromCompiledCode(new_code);
jeffhao725a9572012-11-13 18:20:12 -080091 }
92 }
jeffhao725a9572012-11-13 18:20:12 -080093 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
Brian Carlstromea46f952013-07-30 01:26:50 -070094 mirror::ArtMethod* method = klass->GetVirtualMethod(i);
Jeff Hao02b10d62013-11-06 15:21:24 -080095 if (!method->IsAbstract() && !method->IsProxyMethod()) {
Ian Rogers62d6c772013-02-27 08:32:07 -080096 const void* new_code;
97 if (uninstall) {
Jeff Hao02b10d62013-11-06 15:21:24 -080098 if (forced_interpret_only_ && !method->IsNative()) {
Ian Rogers848871b2013-08-05 10:56:33 -070099 new_code = GetCompiledCodeToInterpreterBridge();
Jeff Hao65d15d92013-07-16 16:39:33 -0700100 } else {
101 new_code = class_linker->GetOatCodeFor(method);
102 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800103 } else { // !uninstall
104 if (!interpreter_stubs_installed_ || method->IsNative()) {
Ian Rogers848871b2013-08-05 10:56:33 -0700105 new_code = GetQuickInstrumentationEntryPoint();
Ian Rogers62d6c772013-02-27 08:32:07 -0800106 } else {
Ian Rogers848871b2013-08-05 10:56:33 -0700107 new_code = GetCompiledCodeToInterpreterBridge();
Ian Rogers62d6c772013-02-27 08:32:07 -0800108 }
109 }
Jeff Haoaa4a7932013-05-13 11:28:27 -0700110 method->SetEntryPointFromCompiledCode(new_code);
jeffhao725a9572012-11-13 18:20:12 -0800111 }
112 }
113 return true;
114}
115
Ian Rogers62d6c772013-02-27 08:32:07 -0800116// Places the instrumentation exit pc as the return PC for every quick frame. This also allows
117// deoptimization of quick frames to interpreter frames.
118static void InstrumentationInstallStack(Thread* thread, void* arg)
Ian Rogers306057f2012-11-26 12:45:53 -0800119 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
120 struct InstallStackVisitor : public StackVisitor {
Ian Rogers62d6c772013-02-27 08:32:07 -0800121 InstallStackVisitor(Thread* thread, Context* context, uintptr_t instrumentation_exit_pc)
122 : StackVisitor(thread, context), instrumentation_stack_(thread->GetInstrumentationStack()),
123 instrumentation_exit_pc_(instrumentation_exit_pc), last_return_pc_(0) {}
jeffhao725a9572012-11-13 18:20:12 -0800124
Ian Rogers306057f2012-11-26 12:45:53 -0800125 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Brian Carlstromea46f952013-07-30 01:26:50 -0700126 mirror::ArtMethod* m = GetMethod();
Ian Rogers306057f2012-11-26 12:45:53 -0800127 if (GetCurrentQuickFrame() == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800128 if (kVerboseInstrumentation) {
129 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId()
130 << " Method=" << PrettyMethod(m);
131 }
Ian Rogers306057f2012-11-26 12:45:53 -0800132 return true; // Ignore shadow frames.
133 }
Ian Rogers306057f2012-11-26 12:45:53 -0800134 if (m == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800135 if (kVerboseInstrumentation) {
136 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
137 }
138 last_return_pc_ = 0;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700139 return true; // Ignore upcalls.
Ian Rogers306057f2012-11-26 12:45:53 -0800140 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800141 if (m->IsRuntimeMethod()) {
142 if (kVerboseInstrumentation) {
143 LOG(INFO) << " Skipping runtime method. Frame " << GetFrameId();
144 }
145 last_return_pc_ = GetReturnPc();
Ian Rogers306057f2012-11-26 12:45:53 -0800146 return true; // Ignore unresolved methods since they will be instrumented after resolution.
147 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800148 if (kVerboseInstrumentation) {
149 LOG(INFO) << " Installing exit stub in " << DescribeLocation();
150 }
151 uintptr_t return_pc = GetReturnPc();
152 CHECK_NE(return_pc, instrumentation_exit_pc_);
153 CHECK_NE(return_pc, 0U);
Jeff Hao9a916d32013-06-27 18:45:37 -0700154 InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, return_pc, GetFrameId(),
155 false);
Ian Rogers62d6c772013-02-27 08:32:07 -0800156 if (kVerboseInstrumentation) {
157 LOG(INFO) << "Pushing frame " << instrumentation_frame.Dump();
158 }
159 instrumentation_stack_->push_back(instrumentation_frame);
160 dex_pcs_.push_back(m->ToDexPc(last_return_pc_));
Ian Rogers306057f2012-11-26 12:45:53 -0800161 SetReturnPc(instrumentation_exit_pc_);
Ian Rogers62d6c772013-02-27 08:32:07 -0800162 last_return_pc_ = return_pc;
Ian Rogers306057f2012-11-26 12:45:53 -0800163 return true; // Continue.
164 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800165 std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
166 std::vector<uint32_t> dex_pcs_;
Ian Rogers306057f2012-11-26 12:45:53 -0800167 const uintptr_t instrumentation_exit_pc_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800168 uintptr_t last_return_pc_;
Ian Rogers306057f2012-11-26 12:45:53 -0800169 };
Ian Rogers62d6c772013-02-27 08:32:07 -0800170 if (kVerboseInstrumentation) {
171 std::string thread_name;
172 thread->GetThreadName(thread_name);
173 LOG(INFO) << "Installing exit stubs in " << thread_name;
Ian Rogers306057f2012-11-26 12:45:53 -0800174 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800175 UniquePtr<Context> context(Context::Create());
Ian Rogers848871b2013-08-05 10:56:33 -0700176 uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
Ian Rogers62d6c772013-02-27 08:32:07 -0800177 InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
178 visitor.WalkStack(true);
179
180 // Create method enter events for all methods current on the thread's stack.
181 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
182 typedef std::deque<InstrumentationStackFrame>::const_reverse_iterator It;
183 for (It it = thread->GetInstrumentationStack()->rbegin(),
184 end = thread->GetInstrumentationStack()->rend(); it != end; ++it) {
185 mirror::Object* this_object = (*it).this_object_;
Brian Carlstromea46f952013-07-30 01:26:50 -0700186 mirror::ArtMethod* method = (*it).method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800187 uint32_t dex_pc = visitor.dex_pcs_.back();
188 visitor.dex_pcs_.pop_back();
189 instrumentation->MethodEnterEvent(thread, this_object, method, dex_pc);
190 }
191 thread->VerifyStack();
Ian Rogers306057f2012-11-26 12:45:53 -0800192}
193
Ian Rogers62d6c772013-02-27 08:32:07 -0800194// Removes the instrumentation exit pc as the return PC for every quick frame.
195static void InstrumentationRestoreStack(Thread* thread, void* arg)
Ian Rogers306057f2012-11-26 12:45:53 -0800196 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
197 struct RestoreStackVisitor : public StackVisitor {
Ian Rogers62d6c772013-02-27 08:32:07 -0800198 RestoreStackVisitor(Thread* thread, uintptr_t instrumentation_exit_pc,
199 Instrumentation* instrumentation)
200 : StackVisitor(thread, NULL), thread_(thread),
201 instrumentation_exit_pc_(instrumentation_exit_pc),
202 instrumentation_(instrumentation),
203 instrumentation_stack_(thread->GetInstrumentationStack()),
204 frames_removed_(0) {}
Ian Rogers306057f2012-11-26 12:45:53 -0800205
206 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800207 if (instrumentation_stack_->size() == 0) {
jeffhao725a9572012-11-13 18:20:12 -0800208 return false; // Stop.
209 }
Brian Carlstromea46f952013-07-30 01:26:50 -0700210 mirror::ArtMethod* m = GetMethod();
Ian Rogers62d6c772013-02-27 08:32:07 -0800211 if (GetCurrentQuickFrame() == NULL) {
212 if (kVerboseInstrumentation) {
213 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId() << " Method=" << PrettyMethod(m);
214 }
215 return true; // Ignore shadow frames.
216 }
Ian Rogers306057f2012-11-26 12:45:53 -0800217 if (m == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800218 if (kVerboseInstrumentation) {
219 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
220 }
Ian Rogers306057f2012-11-26 12:45:53 -0800221 return true; // Ignore upcalls.
222 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800223 bool removed_stub = false;
224 // TODO: make this search more efficient?
Mathieu Chartier02e25112013-08-14 16:14:24 -0700225 for (InstrumentationStackFrame instrumentation_frame : *instrumentation_stack_) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800226 if (instrumentation_frame.frame_id_ == GetFrameId()) {
227 if (kVerboseInstrumentation) {
228 LOG(INFO) << " Removing exit stub in " << DescribeLocation();
229 }
Jeff Hao9a916d32013-06-27 18:45:37 -0700230 if (instrumentation_frame.interpreter_entry_) {
231 CHECK(m == Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
232 } else {
233 CHECK(m == instrumentation_frame.method_) << PrettyMethod(m);
234 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800235 SetReturnPc(instrumentation_frame.return_pc_);
236 // Create the method exit events. As the methods didn't really exit the result is 0.
237 instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m,
238 GetDexPc(), JValue());
239 frames_removed_++;
240 removed_stub = true;
241 break;
242 }
243 }
244 if (!removed_stub) {
245 if (kVerboseInstrumentation) {
246 LOG(INFO) << " No exit stub in " << DescribeLocation();
Ian Rogers306057f2012-11-26 12:45:53 -0800247 }
jeffhao725a9572012-11-13 18:20:12 -0800248 }
249 return true; // Continue.
250 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800251 Thread* const thread_;
Ian Rogers306057f2012-11-26 12:45:53 -0800252 const uintptr_t instrumentation_exit_pc_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800253 Instrumentation* const instrumentation_;
254 std::deque<instrumentation::InstrumentationStackFrame>* const instrumentation_stack_;
255 size_t frames_removed_;
jeffhao725a9572012-11-13 18:20:12 -0800256 };
Ian Rogers62d6c772013-02-27 08:32:07 -0800257 if (kVerboseInstrumentation) {
258 std::string thread_name;
259 thread->GetThreadName(thread_name);
260 LOG(INFO) << "Removing exit stubs in " << thread_name;
261 }
262 std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
263 if (stack->size() > 0) {
264 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
Ian Rogers848871b2013-08-05 10:56:33 -0700265 uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
Ian Rogers62d6c772013-02-27 08:32:07 -0800266 RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
267 visitor.WalkStack(true);
268 CHECK_EQ(visitor.frames_removed_, stack->size());
269 while (stack->size() > 0) {
270 stack->pop_front();
271 }
jeffhao725a9572012-11-13 18:20:12 -0800272 }
273}
274
Ian Rogers62d6c772013-02-27 08:32:07 -0800275void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
276 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
277 bool require_entry_exit_stubs = false;
278 bool require_interpreter = false;
279 if ((events & kMethodEntered) != 0) {
280 method_entry_listeners_.push_back(listener);
Ian Rogers816432e2013-09-06 15:47:45 -0700281 require_interpreter = kDeoptimizeForAccurateMethodEntryExitListeners;
282 require_entry_exit_stubs = !kDeoptimizeForAccurateMethodEntryExitListeners;
Ian Rogers62d6c772013-02-27 08:32:07 -0800283 have_method_entry_listeners_ = true;
284 }
285 if ((events & kMethodExited) != 0) {
286 method_exit_listeners_.push_back(listener);
Ian Rogers816432e2013-09-06 15:47:45 -0700287 require_interpreter = kDeoptimizeForAccurateMethodEntryExitListeners;
288 require_entry_exit_stubs = !kDeoptimizeForAccurateMethodEntryExitListeners;
Ian Rogers62d6c772013-02-27 08:32:07 -0800289 have_method_exit_listeners_ = true;
290 }
291 if ((events & kMethodUnwind) != 0) {
292 method_unwind_listeners_.push_back(listener);
293 have_method_unwind_listeners_ = true;
294 }
295 if ((events & kDexPcMoved) != 0) {
296 dex_pc_listeners_.push_back(listener);
297 require_interpreter = true;
298 have_dex_pc_listeners_ = true;
299 }
Jeff Hao14dd5a82013-04-11 10:23:36 -0700300 if ((events & kExceptionCaught) != 0) {
301 exception_caught_listeners_.push_back(listener);
302 have_exception_caught_listeners_ = true;
303 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800304 ConfigureStubs(require_entry_exit_stubs, require_interpreter);
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200305 UpdateInterpreterHandlerTable();
jeffhao725a9572012-11-13 18:20:12 -0800306}
307
Ian Rogers62d6c772013-02-27 08:32:07 -0800308void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
309 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
310 bool require_entry_exit_stubs = false;
311 bool require_interpreter = false;
312
313 if ((events & kMethodEntered) != 0) {
314 bool contains = std::find(method_entry_listeners_.begin(), method_entry_listeners_.end(),
315 listener) != method_entry_listeners_.end();
316 if (contains) {
317 method_entry_listeners_.remove(listener);
318 }
319 have_method_entry_listeners_ = method_entry_listeners_.size() > 0;
Ian Rogers816432e2013-09-06 15:47:45 -0700320 require_entry_exit_stubs |= have_method_entry_listeners_ &&
321 !kDeoptimizeForAccurateMethodEntryExitListeners;
322 require_interpreter = have_method_entry_listeners_ &&
323 kDeoptimizeForAccurateMethodEntryExitListeners;
Ian Rogers62d6c772013-02-27 08:32:07 -0800324 }
325 if ((events & kMethodExited) != 0) {
326 bool contains = std::find(method_exit_listeners_.begin(), method_exit_listeners_.end(),
327 listener) != method_exit_listeners_.end();
328 if (contains) {
329 method_exit_listeners_.remove(listener);
330 }
331 have_method_exit_listeners_ = method_exit_listeners_.size() > 0;
Ian Rogers816432e2013-09-06 15:47:45 -0700332 require_entry_exit_stubs |= have_method_exit_listeners_ &&
333 !kDeoptimizeForAccurateMethodEntryExitListeners;
334 require_interpreter = have_method_exit_listeners_ &&
335 kDeoptimizeForAccurateMethodEntryExitListeners;
Ian Rogers62d6c772013-02-27 08:32:07 -0800336 }
337 if ((events & kMethodUnwind) != 0) {
338 method_unwind_listeners_.remove(listener);
339 }
340 if ((events & kDexPcMoved) != 0) {
341 bool contains = std::find(dex_pc_listeners_.begin(), dex_pc_listeners_.end(),
342 listener) != dex_pc_listeners_.end();
343 if (contains) {
344 dex_pc_listeners_.remove(listener);
345 }
346 have_dex_pc_listeners_ = dex_pc_listeners_.size() > 0;
347 require_interpreter |= have_dex_pc_listeners_;
348 }
Jeff Hao14dd5a82013-04-11 10:23:36 -0700349 if ((events & kExceptionCaught) != 0) {
350 exception_caught_listeners_.remove(listener);
351 have_exception_caught_listeners_ = exception_caught_listeners_.size() > 0;
352 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800353 ConfigureStubs(require_entry_exit_stubs, require_interpreter);
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200354 UpdateInterpreterHandlerTable();
jeffhao725a9572012-11-13 18:20:12 -0800355}
356
Ian Rogers62d6c772013-02-27 08:32:07 -0800357void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter) {
358 interpret_only_ = require_interpreter || forced_interpret_only_;
359 // Compute what level of instrumentation is required and compare to current.
360 int desired_level, current_level;
361 if (require_interpreter) {
362 desired_level = 2;
363 } else if (require_entry_exit_stubs) {
364 desired_level = 1;
365 } else {
366 desired_level = 0;
367 }
368 if (interpreter_stubs_installed_) {
369 current_level = 2;
370 } else if (entry_exit_stubs_installed_) {
371 current_level = 1;
372 } else {
373 current_level = 0;
374 }
375 if (desired_level == current_level) {
376 // We're already set.
377 return;
378 }
379 Thread* self = Thread::Current();
380 Runtime* runtime = Runtime::Current();
381 Locks::thread_list_lock_->AssertNotHeld(self);
382 if (desired_level > 0) {
383 if (require_interpreter) {
384 interpreter_stubs_installed_ = true;
385 } else {
386 CHECK(require_entry_exit_stubs);
387 entry_exit_stubs_installed_ = true;
388 }
389 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
390 instrumentation_stubs_installed_ = true;
391 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
392 runtime->GetThreadList()->ForEach(InstrumentationInstallStack, this);
393 } else {
394 interpreter_stubs_installed_ = false;
395 entry_exit_stubs_installed_ = false;
396 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
397 instrumentation_stubs_installed_ = false;
398 MutexLock mu(self, *Locks::thread_list_lock_);
399 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
400 }
jeffhao725a9572012-11-13 18:20:12 -0800401}
402
Ian Rogersfa824272013-11-05 16:12:57 -0800403static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
404 thread->ResetQuickAllocEntryPointsForThread();
405}
406
407void Instrumentation::InstrumentQuickAllocEntryPoints() {
408 // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
409 // should be guarded by a lock.
Ian Rogersb122a4b2013-11-19 18:00:50 -0800410 DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_.Load(), 0);
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800411 const bool enable_instrumentation =
Ian Rogersb122a4b2013-11-19 18:00:50 -0800412 quick_alloc_entry_points_instrumentation_counter_.FetchAndAdd(1) == 0;
Ian Rogersfa824272013-11-05 16:12:57 -0800413 if (enable_instrumentation) {
414 // Instrumentation wasn't enabled so enable it.
415 SetQuickAllocEntryPointsInstrumented(true);
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800416 ThreadList* tl = Runtime::Current()->GetThreadList();
417 tl->SuspendAll();
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800418 ResetQuickAllocEntryPoints();
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800419 tl->ResumeAll();
Ian Rogersfa824272013-11-05 16:12:57 -0800420 }
421}
422
423void Instrumentation::UninstrumentQuickAllocEntryPoints() {
424 // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
425 // should be guarded by a lock.
Ian Rogersb122a4b2013-11-19 18:00:50 -0800426 DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_.Load(), 0);
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800427 const bool disable_instrumentation =
Ian Rogersb122a4b2013-11-19 18:00:50 -0800428 quick_alloc_entry_points_instrumentation_counter_.FetchAndSub(1) == 1;
Ian Rogersfa824272013-11-05 16:12:57 -0800429 if (disable_instrumentation) {
430 SetQuickAllocEntryPointsInstrumented(false);
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800431 ThreadList* tl = Runtime::Current()->GetThreadList();
432 tl->SuspendAll();
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800433 ResetQuickAllocEntryPoints();
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800434 tl->ResumeAll();
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800435 }
436}
437
438void Instrumentation::ResetQuickAllocEntryPoints() {
439 Runtime* runtime = Runtime::Current();
440 if (runtime->IsStarted()) {
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800441 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
442 runtime->GetThreadList()->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
Ian Rogersfa824272013-11-05 16:12:57 -0800443 }
444}
445
Brian Carlstromea46f952013-07-30 01:26:50 -0700446void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800447 if (LIKELY(!instrumentation_stubs_installed_)) {
Jeff Haoaa4a7932013-05-13 11:28:27 -0700448 method->SetEntryPointFromCompiledCode(code);
Jeff Hao65d15d92013-07-16 16:39:33 -0700449 } else {
450 if (!interpreter_stubs_installed_ || method->IsNative()) {
Sebastien Hertz5bfd5c92013-11-15 11:36:07 +0100451 // Do not overwrite resolution trampoline. When the trampoline initializes the method's
452 // class, all its static methods' code will be set to the instrumentation entry point.
453 // For more details, see ClassLinker::FixupStaticTrampolines.
454 if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
455 method->SetEntryPointFromCompiledCode(code);
456 } else {
457 method->SetEntryPointFromCompiledCode(GetQuickInstrumentationEntryPoint());
458 }
Jeff Hao65d15d92013-07-16 16:39:33 -0700459 } else {
Ian Rogers848871b2013-08-05 10:56:33 -0700460 method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge());
Jeff Hao65d15d92013-07-16 16:39:33 -0700461 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800462 }
jeffhao725a9572012-11-13 18:20:12 -0800463}
464
Brian Carlstromea46f952013-07-30 01:26:50 -0700465const void* Instrumentation::GetQuickCodeFor(const mirror::ArtMethod* method) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800466 Runtime* runtime = Runtime::Current();
467 if (LIKELY(!instrumentation_stubs_installed_)) {
Jeff Haoaa4a7932013-05-13 11:28:27 -0700468 const void* code = method->GetEntryPointFromCompiledCode();
Ian Rogers62d6c772013-02-27 08:32:07 -0800469 DCHECK(code != NULL);
Ian Rogers848871b2013-08-05 10:56:33 -0700470 if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker()) &&
471 code != GetQuickToInterpreterBridge())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800472 return code;
473 }
474 }
475 return runtime->GetClassLinker()->GetOatCodeFor(method);
jeffhao725a9572012-11-13 18:20:12 -0800476}
477
Ian Rogers62d6c772013-02-27 08:32:07 -0800478void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700479 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800480 uint32_t dex_pc) const {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700481 auto it = method_entry_listeners_.begin();
Jeff Hao65d15d92013-07-16 16:39:33 -0700482 bool is_end = (it == method_entry_listeners_.end());
483 // Implemented this way to prevent problems caused by modification of the list while iterating.
484 while (!is_end) {
485 InstrumentationListener* cur = *it;
486 ++it;
487 is_end = (it == method_entry_listeners_.end());
488 cur->MethodEntered(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800489 }
490}
491
492void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700493 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800494 uint32_t dex_pc, const JValue& return_value) const {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700495 auto it = method_exit_listeners_.begin();
Jeff Hao65d15d92013-07-16 16:39:33 -0700496 bool is_end = (it == method_exit_listeners_.end());
497 // Implemented this way to prevent problems caused by modification of the list while iterating.
498 while (!is_end) {
499 InstrumentationListener* cur = *it;
500 ++it;
501 is_end = (it == method_exit_listeners_.end());
502 cur->MethodExited(thread, this_object, method, dex_pc, return_value);
Ian Rogers62d6c772013-02-27 08:32:07 -0800503 }
504}
505
506void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700507 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800508 uint32_t dex_pc) const {
509 if (have_method_unwind_listeners_) {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700510 for (InstrumentationListener* listener : method_unwind_listeners_) {
Sebastien Hertz51db44a2013-11-19 10:00:29 +0100511 listener->MethodUnwind(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800512 }
513 }
514}
515
516void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700517 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800518 uint32_t dex_pc) const {
519 // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an
520 // action where it can remove itself as a listener and break the iterator. The copy only works
521 // around the problem and in general we may have to move to something like reference counting to
522 // ensure listeners are deleted correctly.
523 std::list<InstrumentationListener*> copy(dex_pc_listeners_);
Mathieu Chartier02e25112013-08-14 16:14:24 -0700524 for (InstrumentationListener* listener : copy) {
525 listener->DexPcMoved(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800526 }
527}
528
529void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
Brian Carlstromea46f952013-07-30 01:26:50 -0700530 mirror::ArtMethod* catch_method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800531 uint32_t catch_dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200532 mirror::Throwable* exception_object) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800533 if (have_exception_caught_listeners_) {
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700534 DCHECK_EQ(thread->GetException(NULL), exception_object);
535 thread->ClearException();
Mathieu Chartier02e25112013-08-14 16:14:24 -0700536 for (InstrumentationListener* listener : exception_caught_listeners_) {
537 listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800538 }
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700539 thread->SetException(throw_location, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800540 }
541}
542
543static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
544 int delta)
545 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
546 size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
547 if (frame_id != instrumentation_frame.frame_id_) {
548 LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
549 << instrumentation_frame.frame_id_;
550 StackVisitor::DescribeStack(self);
551 CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
552 }
553}
554
555void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700556 mirror::ArtMethod* method,
Jeff Hao9a916d32013-06-27 18:45:37 -0700557 uintptr_t lr, bool interpreter_entry) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800558 // We have a callee-save frame meaning this value is guaranteed to never be 0.
559 size_t frame_id = StackVisitor::ComputeNumFrames(self);
560 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
561 if (kVerboseInstrumentation) {
Brian Carlstrom2d888622013-07-18 17:02:00 -0700562 LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << reinterpret_cast<void*>(lr);
Ian Rogers62d6c772013-02-27 08:32:07 -0800563 }
564 instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
Jeff Hao9a916d32013-06-27 18:45:37 -0700565 frame_id, interpreter_entry);
Ian Rogers62d6c772013-02-27 08:32:07 -0800566 stack->push_front(instrumentation_frame);
567
568 MethodEnterEvent(self, this_object, method, 0);
569}
570
571uint64_t Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
572 uint64_t gpr_result, uint64_t fpr_result) {
573 // Do the pop.
574 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
575 CHECK_GT(stack->size(), 0U);
576 InstrumentationStackFrame instrumentation_frame = stack->front();
577 stack->pop_front();
578
579 // Set return PC and check the sanity of the stack.
580 *return_pc = instrumentation_frame.return_pc_;
581 CheckStackDepth(self, instrumentation_frame, 0);
582
Brian Carlstromea46f952013-07-30 01:26:50 -0700583 mirror::ArtMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800584 char return_shorty = MethodHelper(method).GetShorty()[0];
585 JValue return_value;
586 if (return_shorty == 'V') {
587 return_value.SetJ(0);
588 } else if (return_shorty == 'F' || return_shorty == 'D') {
589 return_value.SetJ(fpr_result);
590 } else {
591 return_value.SetJ(gpr_result);
592 }
593 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
594 // return_pc.
595 uint32_t dex_pc = DexFile::kDexNoIndex;
596 mirror::Object* this_object = instrumentation_frame.this_object_;
597 MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
jeffhao725a9572012-11-13 18:20:12 -0800598
Ian Rogers62d6c772013-02-27 08:32:07 -0800599 bool deoptimize = false;
600 if (interpreter_stubs_installed_) {
601 // Deoptimize unless we're returning to an upcall.
602 NthCallerVisitor visitor(self, 1, true);
603 visitor.WalkStack(true);
604 deoptimize = visitor.caller != NULL;
605 if (deoptimize && kVerboseInstrumentation) {
606 LOG(INFO) << "Deoptimizing into " << PrettyMethod(visitor.caller);
607 }
608 }
609 if (deoptimize) {
610 if (kVerboseInstrumentation) {
611 LOG(INFO) << "Deoptimizing from " << PrettyMethod(method)
612 << " result is " << std::hex << return_value.GetJ();
613 }
614 self->SetDeoptimizationReturnValue(return_value);
Ian Rogers848871b2013-08-05 10:56:33 -0700615 return static_cast<uint64_t>(GetQuickDeoptimizationEntryPoint()) |
Ian Rogers62d6c772013-02-27 08:32:07 -0800616 (static_cast<uint64_t>(*return_pc) << 32);
617 } else {
618 if (kVerboseInstrumentation) {
Brian Carlstrom2d888622013-07-18 17:02:00 -0700619 LOG(INFO) << "Returning from " << PrettyMethod(method)
620 << " to PC " << reinterpret_cast<void*>(*return_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800621 }
622 return *return_pc;
623 }
jeffhao725a9572012-11-13 18:20:12 -0800624}
625
Ian Rogers62d6c772013-02-27 08:32:07 -0800626void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
627 // Do the pop.
628 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
629 CHECK_GT(stack->size(), 0U);
630 InstrumentationStackFrame instrumentation_frame = stack->front();
631 // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
632 stack->pop_front();
633
Brian Carlstromea46f952013-07-30 01:26:50 -0700634 mirror::ArtMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800635 if (is_deoptimization) {
636 if (kVerboseInstrumentation) {
637 LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
638 }
639 } else {
640 if (kVerboseInstrumentation) {
641 LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
642 }
643
644 // Notify listeners of method unwind.
645 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
646 // return_pc.
647 uint32_t dex_pc = DexFile::kDexNoIndex;
648 MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
649 }
650}
651
652std::string InstrumentationStackFrame::Dump() const {
653 std::ostringstream os;
654 os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
655 << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
656 return os.str();
657}
658
659} // namespace instrumentation
jeffhao725a9572012-11-13 18:20:12 -0800660} // namespace art