blob: 77ed7b88e34dafe38bf6342f9ae8967ab4ae4f64 [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.
410 DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_, 0U);
411 bool enable_instrumentation = (quick_alloc_entry_points_instrumentation_counter_ == 0);
412 quick_alloc_entry_points_instrumentation_counter_++;
413 if (enable_instrumentation) {
414 // Instrumentation wasn't enabled so enable it.
415 SetQuickAllocEntryPointsInstrumented(true);
416 Runtime* runtime = Runtime::Current();
417 if (runtime->IsStarted()) {
418 ThreadList* tl = runtime->GetThreadList();
419 Thread* self = Thread::Current();
420 tl->SuspendAll();
421 {
422 MutexLock mu(self, *Locks::thread_list_lock_);
423 tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
424 }
425 tl->ResumeAll();
426 }
427 }
428}
429
430void Instrumentation::UninstrumentQuickAllocEntryPoints() {
431 // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
432 // should be guarded by a lock.
433 DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_, 0U);
434 quick_alloc_entry_points_instrumentation_counter_--;
435 bool disable_instrumentation = (quick_alloc_entry_points_instrumentation_counter_ == 0);
436 if (disable_instrumentation) {
437 SetQuickAllocEntryPointsInstrumented(false);
438 Runtime* runtime = Runtime::Current();
439 if (runtime->IsStarted()) {
440 ThreadList* tl = Runtime::Current()->GetThreadList();
441 Thread* self = Thread::Current();
442 tl->SuspendAll();
443 {
444 MutexLock mu(self, *Locks::thread_list_lock_);
445 tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
446 }
447 tl->ResumeAll();
448 }
449 }
450}
451
Brian Carlstromea46f952013-07-30 01:26:50 -0700452void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800453 if (LIKELY(!instrumentation_stubs_installed_)) {
Jeff Haoaa4a7932013-05-13 11:28:27 -0700454 method->SetEntryPointFromCompiledCode(code);
Jeff Hao65d15d92013-07-16 16:39:33 -0700455 } else {
456 if (!interpreter_stubs_installed_ || method->IsNative()) {
Sebastien Hertz5bfd5c92013-11-15 11:36:07 +0100457 // Do not overwrite resolution trampoline. When the trampoline initializes the method's
458 // class, all its static methods' code will be set to the instrumentation entry point.
459 // For more details, see ClassLinker::FixupStaticTrampolines.
460 if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
461 method->SetEntryPointFromCompiledCode(code);
462 } else {
463 method->SetEntryPointFromCompiledCode(GetQuickInstrumentationEntryPoint());
464 }
Jeff Hao65d15d92013-07-16 16:39:33 -0700465 } else {
Ian Rogers848871b2013-08-05 10:56:33 -0700466 method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge());
Jeff Hao65d15d92013-07-16 16:39:33 -0700467 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800468 }
jeffhao725a9572012-11-13 18:20:12 -0800469}
470
Brian Carlstromea46f952013-07-30 01:26:50 -0700471const void* Instrumentation::GetQuickCodeFor(const mirror::ArtMethod* method) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800472 Runtime* runtime = Runtime::Current();
473 if (LIKELY(!instrumentation_stubs_installed_)) {
Jeff Haoaa4a7932013-05-13 11:28:27 -0700474 const void* code = method->GetEntryPointFromCompiledCode();
Ian Rogers62d6c772013-02-27 08:32:07 -0800475 DCHECK(code != NULL);
Ian Rogers848871b2013-08-05 10:56:33 -0700476 if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker()) &&
477 code != GetQuickToInterpreterBridge())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800478 return code;
479 }
480 }
481 return runtime->GetClassLinker()->GetOatCodeFor(method);
jeffhao725a9572012-11-13 18:20:12 -0800482}
483
Ian Rogers62d6c772013-02-27 08:32:07 -0800484void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700485 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800486 uint32_t dex_pc) const {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700487 auto it = method_entry_listeners_.begin();
Jeff Hao65d15d92013-07-16 16:39:33 -0700488 bool is_end = (it == method_entry_listeners_.end());
489 // Implemented this way to prevent problems caused by modification of the list while iterating.
490 while (!is_end) {
491 InstrumentationListener* cur = *it;
492 ++it;
493 is_end = (it == method_entry_listeners_.end());
494 cur->MethodEntered(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800495 }
496}
497
498void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700499 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800500 uint32_t dex_pc, const JValue& return_value) const {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700501 auto it = method_exit_listeners_.begin();
Jeff Hao65d15d92013-07-16 16:39:33 -0700502 bool is_end = (it == method_exit_listeners_.end());
503 // Implemented this way to prevent problems caused by modification of the list while iterating.
504 while (!is_end) {
505 InstrumentationListener* cur = *it;
506 ++it;
507 is_end = (it == method_exit_listeners_.end());
508 cur->MethodExited(thread, this_object, method, dex_pc, return_value);
Ian Rogers62d6c772013-02-27 08:32:07 -0800509 }
510}
511
512void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700513 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800514 uint32_t dex_pc) const {
515 if (have_method_unwind_listeners_) {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700516 for (InstrumentationListener* listener : method_unwind_listeners_) {
517 listener->MethodUnwind(thread, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800518 }
519 }
520}
521
522void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700523 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800524 uint32_t dex_pc) const {
525 // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an
526 // action where it can remove itself as a listener and break the iterator. The copy only works
527 // around the problem and in general we may have to move to something like reference counting to
528 // ensure listeners are deleted correctly.
529 std::list<InstrumentationListener*> copy(dex_pc_listeners_);
Mathieu Chartier02e25112013-08-14 16:14:24 -0700530 for (InstrumentationListener* listener : copy) {
531 listener->DexPcMoved(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800532 }
533}
534
535void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
Brian Carlstromea46f952013-07-30 01:26:50 -0700536 mirror::ArtMethod* catch_method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800537 uint32_t catch_dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200538 mirror::Throwable* exception_object) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800539 if (have_exception_caught_listeners_) {
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700540 DCHECK_EQ(thread->GetException(NULL), exception_object);
541 thread->ClearException();
Mathieu Chartier02e25112013-08-14 16:14:24 -0700542 for (InstrumentationListener* listener : exception_caught_listeners_) {
543 listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800544 }
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700545 thread->SetException(throw_location, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800546 }
547}
548
549static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
550 int delta)
551 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
552 size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
553 if (frame_id != instrumentation_frame.frame_id_) {
554 LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
555 << instrumentation_frame.frame_id_;
556 StackVisitor::DescribeStack(self);
557 CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
558 }
559}
560
561void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700562 mirror::ArtMethod* method,
Jeff Hao9a916d32013-06-27 18:45:37 -0700563 uintptr_t lr, bool interpreter_entry) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800564 // We have a callee-save frame meaning this value is guaranteed to never be 0.
565 size_t frame_id = StackVisitor::ComputeNumFrames(self);
566 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
567 if (kVerboseInstrumentation) {
Brian Carlstrom2d888622013-07-18 17:02:00 -0700568 LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << reinterpret_cast<void*>(lr);
Ian Rogers62d6c772013-02-27 08:32:07 -0800569 }
570 instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
Jeff Hao9a916d32013-06-27 18:45:37 -0700571 frame_id, interpreter_entry);
Ian Rogers62d6c772013-02-27 08:32:07 -0800572 stack->push_front(instrumentation_frame);
573
574 MethodEnterEvent(self, this_object, method, 0);
575}
576
577uint64_t Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
578 uint64_t gpr_result, uint64_t fpr_result) {
579 // Do the pop.
580 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
581 CHECK_GT(stack->size(), 0U);
582 InstrumentationStackFrame instrumentation_frame = stack->front();
583 stack->pop_front();
584
585 // Set return PC and check the sanity of the stack.
586 *return_pc = instrumentation_frame.return_pc_;
587 CheckStackDepth(self, instrumentation_frame, 0);
588
Brian Carlstromea46f952013-07-30 01:26:50 -0700589 mirror::ArtMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800590 char return_shorty = MethodHelper(method).GetShorty()[0];
591 JValue return_value;
592 if (return_shorty == 'V') {
593 return_value.SetJ(0);
594 } else if (return_shorty == 'F' || return_shorty == 'D') {
595 return_value.SetJ(fpr_result);
596 } else {
597 return_value.SetJ(gpr_result);
598 }
599 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
600 // return_pc.
601 uint32_t dex_pc = DexFile::kDexNoIndex;
602 mirror::Object* this_object = instrumentation_frame.this_object_;
603 MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
jeffhao725a9572012-11-13 18:20:12 -0800604
Ian Rogers62d6c772013-02-27 08:32:07 -0800605 bool deoptimize = false;
606 if (interpreter_stubs_installed_) {
607 // Deoptimize unless we're returning to an upcall.
608 NthCallerVisitor visitor(self, 1, true);
609 visitor.WalkStack(true);
610 deoptimize = visitor.caller != NULL;
611 if (deoptimize && kVerboseInstrumentation) {
612 LOG(INFO) << "Deoptimizing into " << PrettyMethod(visitor.caller);
613 }
614 }
615 if (deoptimize) {
616 if (kVerboseInstrumentation) {
617 LOG(INFO) << "Deoptimizing from " << PrettyMethod(method)
618 << " result is " << std::hex << return_value.GetJ();
619 }
620 self->SetDeoptimizationReturnValue(return_value);
Ian Rogers848871b2013-08-05 10:56:33 -0700621 return static_cast<uint64_t>(GetQuickDeoptimizationEntryPoint()) |
Ian Rogers62d6c772013-02-27 08:32:07 -0800622 (static_cast<uint64_t>(*return_pc) << 32);
623 } else {
624 if (kVerboseInstrumentation) {
Brian Carlstrom2d888622013-07-18 17:02:00 -0700625 LOG(INFO) << "Returning from " << PrettyMethod(method)
626 << " to PC " << reinterpret_cast<void*>(*return_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800627 }
628 return *return_pc;
629 }
jeffhao725a9572012-11-13 18:20:12 -0800630}
631
Ian Rogers62d6c772013-02-27 08:32:07 -0800632void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
633 // Do the pop.
634 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
635 CHECK_GT(stack->size(), 0U);
636 InstrumentationStackFrame instrumentation_frame = stack->front();
637 // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
638 stack->pop_front();
639
Brian Carlstromea46f952013-07-30 01:26:50 -0700640 mirror::ArtMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800641 if (is_deoptimization) {
642 if (kVerboseInstrumentation) {
643 LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
644 }
645 } else {
646 if (kVerboseInstrumentation) {
647 LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
648 }
649
650 // Notify listeners of method unwind.
651 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
652 // return_pc.
653 uint32_t dex_pc = DexFile::kDexNoIndex;
654 MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
655 }
656}
657
658std::string InstrumentationStackFrame::Dump() const {
659 std::ostringstream os;
660 os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
661 << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
662 return os.str();
663}
664
665} // namespace instrumentation
jeffhao725a9572012-11-13 18:20:12 -0800666} // namespace art