blob: 091f66adce82fedb123e145f023ce2bce7be5b59 [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"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080026#include "mirror/class-inl.h"
27#include "mirror/dex_cache.h"
28#include "mirror/abstract_method-inl.h"
29#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)
jeffhao725a9572012-11-13 18:20:12 -080033#include "oat/runtime/oat_support_entrypoints.h"
34#endif
35#include "object_utils.h"
36#include "os.h"
37#include "scoped_thread_state_change.h"
38#include "thread.h"
39#include "thread_list.h"
jeffhao725a9572012-11-13 18:20:12 -080040
41namespace art {
Ian Rogers62d6c772013-02-27 08:32:07 -080042namespace instrumentation {
jeffhao725a9572012-11-13 18:20:12 -080043
Ian Rogers62d6c772013-02-27 08:32:07 -080044static bool InstallStubsClassVisitor(mirror::Class* klass, void* arg)
jeffhao725a9572012-11-13 18:20:12 -080045 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -080046 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
47 return instrumentation->InstallStubsForClass(klass);
48}
49
50bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
51 bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
52 ClassLinker* class_linker = NULL;
53 if (uninstall) {
54 class_linker = Runtime::Current()->GetClassLinker();
55 }
56 bool is_initialized = klass->IsInitialized();
jeffhao725a9572012-11-13 18:20:12 -080057 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080058 mirror::AbstractMethod* method = klass->GetDirectMethod(i);
Ian Rogers62d6c772013-02-27 08:32:07 -080059 if (!method->IsAbstract()) {
60 const void* new_code;
61 if (uninstall) {
Jeff Hao65d15d92013-07-16 16:39:33 -070062 if (forced_interpret_only_ && !method->IsNative() && !method->IsProxyMethod()) {
63 new_code = GetInterpreterEntryPoint();
64 } else if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
Ian Rogers62d6c772013-02-27 08:32:07 -080065 new_code = class_linker->GetOatCodeFor(method);
66 } else {
Jeff Hao0aba0ba2013-06-03 14:49:28 -070067 new_code = GetResolutionTrampoline(class_linker);
Ian Rogers62d6c772013-02-27 08:32:07 -080068 }
69 } else { // !uninstall
70 if (!interpreter_stubs_installed_ || method->IsNative()) {
71 new_code = GetInstrumentationEntryPoint();
72 } else {
73 new_code = GetInterpreterEntryPoint();
74 }
75 }
Jeff Haoaa4a7932013-05-13 11:28:27 -070076 method->SetEntryPointFromCompiledCode(new_code);
jeffhao725a9572012-11-13 18:20:12 -080077 }
78 }
jeffhao725a9572012-11-13 18:20:12 -080079 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080080 mirror::AbstractMethod* method = klass->GetVirtualMethod(i);
Ian Rogers62d6c772013-02-27 08:32:07 -080081 if (!method->IsAbstract()) {
82 const void* new_code;
83 if (uninstall) {
Jeff Hao65d15d92013-07-16 16:39:33 -070084 if (forced_interpret_only_ && !method->IsNative() && !method->IsProxyMethod()) {
85 new_code = GetInterpreterEntryPoint();
86 } else {
87 new_code = class_linker->GetOatCodeFor(method);
88 }
Ian Rogers62d6c772013-02-27 08:32:07 -080089 } else { // !uninstall
90 if (!interpreter_stubs_installed_ || method->IsNative()) {
91 new_code = GetInstrumentationEntryPoint();
92 } else {
93 new_code = GetInterpreterEntryPoint();
94 }
95 }
Jeff Haoaa4a7932013-05-13 11:28:27 -070096 method->SetEntryPointFromCompiledCode(new_code);
jeffhao725a9572012-11-13 18:20:12 -080097 }
98 }
99 return true;
100}
101
Ian Rogers62d6c772013-02-27 08:32:07 -0800102// Places the instrumentation exit pc as the return PC for every quick frame. This also allows
103// deoptimization of quick frames to interpreter frames.
104static void InstrumentationInstallStack(Thread* thread, void* arg)
Ian Rogers306057f2012-11-26 12:45:53 -0800105 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
106 struct InstallStackVisitor : public StackVisitor {
Ian Rogers62d6c772013-02-27 08:32:07 -0800107 InstallStackVisitor(Thread* thread, Context* context, uintptr_t instrumentation_exit_pc)
108 : StackVisitor(thread, context), instrumentation_stack_(thread->GetInstrumentationStack()),
109 instrumentation_exit_pc_(instrumentation_exit_pc), last_return_pc_(0) {}
jeffhao725a9572012-11-13 18:20:12 -0800110
Ian Rogers306057f2012-11-26 12:45:53 -0800111 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800112 mirror::AbstractMethod* m = GetMethod();
Ian Rogers306057f2012-11-26 12:45:53 -0800113 if (GetCurrentQuickFrame() == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800114 if (kVerboseInstrumentation) {
115 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId()
116 << " Method=" << PrettyMethod(m);
117 }
Ian Rogers306057f2012-11-26 12:45:53 -0800118 return true; // Ignore shadow frames.
119 }
Ian Rogers306057f2012-11-26 12:45:53 -0800120 if (m == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800121 if (kVerboseInstrumentation) {
122 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
123 }
124 last_return_pc_ = 0;
Ian Rogers306057f2012-11-26 12:45:53 -0800125 return true; // Ignore upcalls.
126 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800127 if (m->IsRuntimeMethod()) {
128 if (kVerboseInstrumentation) {
129 LOG(INFO) << " Skipping runtime method. Frame " << GetFrameId();
130 }
131 last_return_pc_ = GetReturnPc();
Ian Rogers306057f2012-11-26 12:45:53 -0800132 return true; // Ignore unresolved methods since they will be instrumented after resolution.
133 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800134 if (kVerboseInstrumentation) {
135 LOG(INFO) << " Installing exit stub in " << DescribeLocation();
136 }
137 uintptr_t return_pc = GetReturnPc();
138 CHECK_NE(return_pc, instrumentation_exit_pc_);
139 CHECK_NE(return_pc, 0U);
Jeff Hao9a916d32013-06-27 18:45:37 -0700140 InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, return_pc, GetFrameId(),
141 false);
Ian Rogers62d6c772013-02-27 08:32:07 -0800142 if (kVerboseInstrumentation) {
143 LOG(INFO) << "Pushing frame " << instrumentation_frame.Dump();
144 }
145 instrumentation_stack_->push_back(instrumentation_frame);
146 dex_pcs_.push_back(m->ToDexPc(last_return_pc_));
Ian Rogers306057f2012-11-26 12:45:53 -0800147 SetReturnPc(instrumentation_exit_pc_);
Ian Rogers62d6c772013-02-27 08:32:07 -0800148 last_return_pc_ = return_pc;
Ian Rogers306057f2012-11-26 12:45:53 -0800149 return true; // Continue.
150 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800151 std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
152 std::vector<uint32_t> dex_pcs_;
Ian Rogers306057f2012-11-26 12:45:53 -0800153 const uintptr_t instrumentation_exit_pc_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800154 uintptr_t last_return_pc_;
Ian Rogers306057f2012-11-26 12:45:53 -0800155 };
Ian Rogers62d6c772013-02-27 08:32:07 -0800156 if (kVerboseInstrumentation) {
157 std::string thread_name;
158 thread->GetThreadName(thread_name);
159 LOG(INFO) << "Installing exit stubs in " << thread_name;
Ian Rogers306057f2012-11-26 12:45:53 -0800160 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800161 UniquePtr<Context> context(Context::Create());
162 uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
163 InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
164 visitor.WalkStack(true);
165
166 // Create method enter events for all methods current on the thread's stack.
167 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
168 typedef std::deque<InstrumentationStackFrame>::const_reverse_iterator It;
169 for (It it = thread->GetInstrumentationStack()->rbegin(),
170 end = thread->GetInstrumentationStack()->rend(); it != end; ++it) {
171 mirror::Object* this_object = (*it).this_object_;
172 mirror::AbstractMethod* method = (*it).method_;
173 uint32_t dex_pc = visitor.dex_pcs_.back();
174 visitor.dex_pcs_.pop_back();
175 instrumentation->MethodEnterEvent(thread, this_object, method, dex_pc);
176 }
177 thread->VerifyStack();
Ian Rogers306057f2012-11-26 12:45:53 -0800178}
179
Ian Rogers62d6c772013-02-27 08:32:07 -0800180// Removes the instrumentation exit pc as the return PC for every quick frame.
181static void InstrumentationRestoreStack(Thread* thread, void* arg)
Ian Rogers306057f2012-11-26 12:45:53 -0800182 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
183 struct RestoreStackVisitor : public StackVisitor {
Ian Rogers62d6c772013-02-27 08:32:07 -0800184 RestoreStackVisitor(Thread* thread, uintptr_t instrumentation_exit_pc,
185 Instrumentation* instrumentation)
186 : StackVisitor(thread, NULL), thread_(thread),
187 instrumentation_exit_pc_(instrumentation_exit_pc),
188 instrumentation_(instrumentation),
189 instrumentation_stack_(thread->GetInstrumentationStack()),
190 frames_removed_(0) {}
Ian Rogers306057f2012-11-26 12:45:53 -0800191
192 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800193 if (instrumentation_stack_->size() == 0) {
jeffhao725a9572012-11-13 18:20:12 -0800194 return false; // Stop.
195 }
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800196 mirror::AbstractMethod* m = GetMethod();
Ian Rogers62d6c772013-02-27 08:32:07 -0800197 if (GetCurrentQuickFrame() == NULL) {
198 if (kVerboseInstrumentation) {
199 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId() << " Method=" << PrettyMethod(m);
200 }
201 return true; // Ignore shadow frames.
202 }
Ian Rogers306057f2012-11-26 12:45:53 -0800203 if (m == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800204 if (kVerboseInstrumentation) {
205 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
206 }
Ian Rogers306057f2012-11-26 12:45:53 -0800207 return true; // Ignore upcalls.
208 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800209 typedef std::deque<instrumentation::InstrumentationStackFrame>::const_iterator It; // TODO: C++0x auto
210 bool removed_stub = false;
211 // TODO: make this search more efficient?
212 for (It it = instrumentation_stack_->begin(), end = instrumentation_stack_->end(); it != end;
213 ++it) {
214 InstrumentationStackFrame instrumentation_frame = *it;
215 if (instrumentation_frame.frame_id_ == GetFrameId()) {
216 if (kVerboseInstrumentation) {
217 LOG(INFO) << " Removing exit stub in " << DescribeLocation();
218 }
Jeff Hao9a916d32013-06-27 18:45:37 -0700219 if (instrumentation_frame.interpreter_entry_) {
220 CHECK(m == Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
221 } else {
222 CHECK(m == instrumentation_frame.method_) << PrettyMethod(m);
223 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800224 SetReturnPc(instrumentation_frame.return_pc_);
225 // Create the method exit events. As the methods didn't really exit the result is 0.
226 instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m,
227 GetDexPc(), JValue());
228 frames_removed_++;
229 removed_stub = true;
230 break;
231 }
232 }
233 if (!removed_stub) {
234 if (kVerboseInstrumentation) {
235 LOG(INFO) << " No exit stub in " << DescribeLocation();
Ian Rogers306057f2012-11-26 12:45:53 -0800236 }
jeffhao725a9572012-11-13 18:20:12 -0800237 }
238 return true; // Continue.
239 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800240 Thread* const thread_;
Ian Rogers306057f2012-11-26 12:45:53 -0800241 const uintptr_t instrumentation_exit_pc_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800242 Instrumentation* const instrumentation_;
243 std::deque<instrumentation::InstrumentationStackFrame>* const instrumentation_stack_;
244 size_t frames_removed_;
jeffhao725a9572012-11-13 18:20:12 -0800245 };
Ian Rogers62d6c772013-02-27 08:32:07 -0800246 if (kVerboseInstrumentation) {
247 std::string thread_name;
248 thread->GetThreadName(thread_name);
249 LOG(INFO) << "Removing exit stubs in " << thread_name;
250 }
251 std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
252 if (stack->size() > 0) {
253 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
254 uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
255 RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
256 visitor.WalkStack(true);
257 CHECK_EQ(visitor.frames_removed_, stack->size());
258 while (stack->size() > 0) {
259 stack->pop_front();
260 }
jeffhao725a9572012-11-13 18:20:12 -0800261 }
262}
263
Ian Rogers62d6c772013-02-27 08:32:07 -0800264void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
265 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
266 bool require_entry_exit_stubs = false;
267 bool require_interpreter = false;
268 if ((events & kMethodEntered) != 0) {
269 method_entry_listeners_.push_back(listener);
270 require_entry_exit_stubs = true;
271 have_method_entry_listeners_ = true;
272 }
273 if ((events & kMethodExited) != 0) {
274 method_exit_listeners_.push_back(listener);
275 require_entry_exit_stubs = true;
276 have_method_exit_listeners_ = true;
277 }
278 if ((events & kMethodUnwind) != 0) {
279 method_unwind_listeners_.push_back(listener);
280 have_method_unwind_listeners_ = true;
281 }
282 if ((events & kDexPcMoved) != 0) {
283 dex_pc_listeners_.push_back(listener);
284 require_interpreter = true;
285 have_dex_pc_listeners_ = true;
286 }
Jeff Hao14dd5a82013-04-11 10:23:36 -0700287 if ((events & kExceptionCaught) != 0) {
288 exception_caught_listeners_.push_back(listener);
289 have_exception_caught_listeners_ = true;
290 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800291 ConfigureStubs(require_entry_exit_stubs, require_interpreter);
jeffhao725a9572012-11-13 18:20:12 -0800292}
293
Ian Rogers62d6c772013-02-27 08:32:07 -0800294void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
295 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
296 bool require_entry_exit_stubs = false;
297 bool require_interpreter = false;
298
299 if ((events & kMethodEntered) != 0) {
300 bool contains = std::find(method_entry_listeners_.begin(), method_entry_listeners_.end(),
301 listener) != method_entry_listeners_.end();
302 if (contains) {
303 method_entry_listeners_.remove(listener);
304 }
305 have_method_entry_listeners_ = method_entry_listeners_.size() > 0;
306 require_entry_exit_stubs |= have_method_entry_listeners_;
307 }
308 if ((events & kMethodExited) != 0) {
309 bool contains = std::find(method_exit_listeners_.begin(), method_exit_listeners_.end(),
310 listener) != method_exit_listeners_.end();
311 if (contains) {
312 method_exit_listeners_.remove(listener);
313 }
314 have_method_exit_listeners_ = method_exit_listeners_.size() > 0;
315 require_entry_exit_stubs |= have_method_exit_listeners_;
316 }
317 if ((events & kMethodUnwind) != 0) {
318 method_unwind_listeners_.remove(listener);
319 }
320 if ((events & kDexPcMoved) != 0) {
321 bool contains = std::find(dex_pc_listeners_.begin(), dex_pc_listeners_.end(),
322 listener) != dex_pc_listeners_.end();
323 if (contains) {
324 dex_pc_listeners_.remove(listener);
325 }
326 have_dex_pc_listeners_ = dex_pc_listeners_.size() > 0;
327 require_interpreter |= have_dex_pc_listeners_;
328 }
Jeff Hao14dd5a82013-04-11 10:23:36 -0700329 if ((events & kExceptionCaught) != 0) {
330 exception_caught_listeners_.remove(listener);
331 have_exception_caught_listeners_ = exception_caught_listeners_.size() > 0;
332 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800333 ConfigureStubs(require_entry_exit_stubs, require_interpreter);
jeffhao725a9572012-11-13 18:20:12 -0800334}
335
Ian Rogers62d6c772013-02-27 08:32:07 -0800336void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter) {
337 interpret_only_ = require_interpreter || forced_interpret_only_;
338 // Compute what level of instrumentation is required and compare to current.
339 int desired_level, current_level;
340 if (require_interpreter) {
341 desired_level = 2;
342 } else if (require_entry_exit_stubs) {
343 desired_level = 1;
344 } else {
345 desired_level = 0;
346 }
347 if (interpreter_stubs_installed_) {
348 current_level = 2;
349 } else if (entry_exit_stubs_installed_) {
350 current_level = 1;
351 } else {
352 current_level = 0;
353 }
354 if (desired_level == current_level) {
355 // We're already set.
356 return;
357 }
358 Thread* self = Thread::Current();
359 Runtime* runtime = Runtime::Current();
360 Locks::thread_list_lock_->AssertNotHeld(self);
361 if (desired_level > 0) {
362 if (require_interpreter) {
363 interpreter_stubs_installed_ = true;
364 } else {
365 CHECK(require_entry_exit_stubs);
366 entry_exit_stubs_installed_ = true;
367 }
368 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
369 instrumentation_stubs_installed_ = true;
370 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
371 runtime->GetThreadList()->ForEach(InstrumentationInstallStack, this);
372 } else {
373 interpreter_stubs_installed_ = false;
374 entry_exit_stubs_installed_ = false;
375 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
376 instrumentation_stubs_installed_ = false;
377 MutexLock mu(self, *Locks::thread_list_lock_);
378 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
379 }
jeffhao725a9572012-11-13 18:20:12 -0800380}
381
Ian Rogers62d6c772013-02-27 08:32:07 -0800382void Instrumentation::UpdateMethodsCode(mirror::AbstractMethod* method, const void* code) const {
383 if (LIKELY(!instrumentation_stubs_installed_)) {
Jeff Haoaa4a7932013-05-13 11:28:27 -0700384 method->SetEntryPointFromCompiledCode(code);
Jeff Hao65d15d92013-07-16 16:39:33 -0700385 } else {
386 if (!interpreter_stubs_installed_ || method->IsNative()) {
387 method->SetEntryPointFromCompiledCode(GetInstrumentationEntryPoint());
388 } else {
389 method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
390 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800391 }
jeffhao725a9572012-11-13 18:20:12 -0800392}
393
Ian Rogers62d6c772013-02-27 08:32:07 -0800394const void* Instrumentation::GetQuickCodeFor(const mirror::AbstractMethod* method) const {
395 Runtime* runtime = Runtime::Current();
396 if (LIKELY(!instrumentation_stubs_installed_)) {
Jeff Haoaa4a7932013-05-13 11:28:27 -0700397 const void* code = method->GetEntryPointFromCompiledCode();
Ian Rogers62d6c772013-02-27 08:32:07 -0800398 DCHECK(code != NULL);
Jeff Haof3e861d2013-07-03 15:42:17 -0700399 if (LIKELY(code != GetResolutionTrampoline(runtime->GetClassLinker()) &&
400 code != GetInterpreterEntryPoint())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800401 return code;
402 }
403 }
404 return runtime->GetClassLinker()->GetOatCodeFor(method);
jeffhao725a9572012-11-13 18:20:12 -0800405}
406
Ian Rogers62d6c772013-02-27 08:32:07 -0800407void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
408 const mirror::AbstractMethod* method,
409 uint32_t dex_pc) const {
410 typedef std::list<InstrumentationListener*>::const_iterator It; // TODO: C++0x auto
Jeff Hao65d15d92013-07-16 16:39:33 -0700411 It it = method_entry_listeners_.begin();
412 bool is_end = (it == method_entry_listeners_.end());
413 // Implemented this way to prevent problems caused by modification of the list while iterating.
414 while (!is_end) {
415 InstrumentationListener* cur = *it;
416 ++it;
417 is_end = (it == method_entry_listeners_.end());
418 cur->MethodEntered(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800419 }
420}
421
422void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
423 const mirror::AbstractMethod* method,
424 uint32_t dex_pc, const JValue& return_value) const {
425 typedef std::list<InstrumentationListener*>::const_iterator It; // TODO: C++0x auto
Jeff Hao65d15d92013-07-16 16:39:33 -0700426 It it = method_exit_listeners_.begin();
427 bool is_end = (it == method_exit_listeners_.end());
428 // Implemented this way to prevent problems caused by modification of the list while iterating.
429 while (!is_end) {
430 InstrumentationListener* cur = *it;
431 ++it;
432 is_end = (it == method_exit_listeners_.end());
433 cur->MethodExited(thread, this_object, method, dex_pc, return_value);
Ian Rogers62d6c772013-02-27 08:32:07 -0800434 }
435}
436
437void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
438 const mirror::AbstractMethod* method,
439 uint32_t dex_pc) const {
440 if (have_method_unwind_listeners_) {
441 typedef std::list<InstrumentationListener*>::const_iterator It; // TODO: C++0x auto
442 for (It it = method_unwind_listeners_.begin(), end = method_unwind_listeners_.end(); it != end;
443 ++it) {
444 (*it)->MethodUnwind(thread, method, dex_pc);
445 }
446 }
447}
448
449void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
450 const mirror::AbstractMethod* method,
451 uint32_t dex_pc) const {
452 // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an
453 // action where it can remove itself as a listener and break the iterator. The copy only works
454 // around the problem and in general we may have to move to something like reference counting to
455 // ensure listeners are deleted correctly.
456 std::list<InstrumentationListener*> copy(dex_pc_listeners_);
457 typedef std::list<InstrumentationListener*>::const_iterator It; // TODO: C++0x auto
458 for (It it = copy.begin(), end = copy.end(); it != end; ++it) {
459 (*it)->DexPcMoved(thread, this_object, method, dex_pc);
460 }
461}
462
463void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
464 mirror::AbstractMethod* catch_method,
465 uint32_t catch_dex_pc,
466 mirror::Throwable* exception_object) {
467 if (have_exception_caught_listeners_) {
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700468 DCHECK_EQ(thread->GetException(NULL), exception_object);
469 thread->ClearException();
Ian Rogers62d6c772013-02-27 08:32:07 -0800470 typedef std::list<InstrumentationListener*>::const_iterator It; // TODO: C++0x auto
471 for (It it = exception_caught_listeners_.begin(), end = exception_caught_listeners_.end();
472 it != end; ++it) {
473 (*it)->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
474 }
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700475 thread->SetException(throw_location, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800476 }
477}
478
479static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
480 int delta)
481 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
482 size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
483 if (frame_id != instrumentation_frame.frame_id_) {
484 LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
485 << instrumentation_frame.frame_id_;
486 StackVisitor::DescribeStack(self);
487 CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
488 }
489}
490
491void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
492 mirror::AbstractMethod* method,
Jeff Hao9a916d32013-06-27 18:45:37 -0700493 uintptr_t lr, bool interpreter_entry) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800494 // We have a callee-save frame meaning this value is guaranteed to never be 0.
495 size_t frame_id = StackVisitor::ComputeNumFrames(self);
496 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
497 if (kVerboseInstrumentation) {
498 LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << (void*)lr;
499 }
500 instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
Jeff Hao9a916d32013-06-27 18:45:37 -0700501 frame_id, interpreter_entry);
Ian Rogers62d6c772013-02-27 08:32:07 -0800502 stack->push_front(instrumentation_frame);
503
504 MethodEnterEvent(self, this_object, method, 0);
505}
506
507uint64_t Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
508 uint64_t gpr_result, uint64_t fpr_result) {
509 // Do the pop.
510 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
511 CHECK_GT(stack->size(), 0U);
512 InstrumentationStackFrame instrumentation_frame = stack->front();
513 stack->pop_front();
514
515 // Set return PC and check the sanity of the stack.
516 *return_pc = instrumentation_frame.return_pc_;
517 CheckStackDepth(self, instrumentation_frame, 0);
518
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800519 mirror::AbstractMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800520 char return_shorty = MethodHelper(method).GetShorty()[0];
521 JValue return_value;
522 if (return_shorty == 'V') {
523 return_value.SetJ(0);
524 } else if (return_shorty == 'F' || return_shorty == 'D') {
525 return_value.SetJ(fpr_result);
526 } else {
527 return_value.SetJ(gpr_result);
528 }
529 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
530 // return_pc.
531 uint32_t dex_pc = DexFile::kDexNoIndex;
532 mirror::Object* this_object = instrumentation_frame.this_object_;
533 MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
jeffhao725a9572012-11-13 18:20:12 -0800534
Ian Rogers62d6c772013-02-27 08:32:07 -0800535 bool deoptimize = false;
536 if (interpreter_stubs_installed_) {
537 // Deoptimize unless we're returning to an upcall.
538 NthCallerVisitor visitor(self, 1, true);
539 visitor.WalkStack(true);
540 deoptimize = visitor.caller != NULL;
541 if (deoptimize && kVerboseInstrumentation) {
542 LOG(INFO) << "Deoptimizing into " << PrettyMethod(visitor.caller);
543 }
544 }
545 if (deoptimize) {
546 if (kVerboseInstrumentation) {
547 LOG(INFO) << "Deoptimizing from " << PrettyMethod(method)
548 << " result is " << std::hex << return_value.GetJ();
549 }
550 self->SetDeoptimizationReturnValue(return_value);
551 return static_cast<uint64_t>(GetDeoptimizationEntryPoint()) |
552 (static_cast<uint64_t>(*return_pc) << 32);
553 } else {
554 if (kVerboseInstrumentation) {
555 LOG(INFO) << "Returning from " << PrettyMethod(method) << " to PC " << (void*)(*return_pc);
556 }
557 return *return_pc;
558 }
jeffhao725a9572012-11-13 18:20:12 -0800559}
560
Ian Rogers62d6c772013-02-27 08:32:07 -0800561void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
562 // Do the pop.
563 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
564 CHECK_GT(stack->size(), 0U);
565 InstrumentationStackFrame instrumentation_frame = stack->front();
566 // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
567 stack->pop_front();
568
569 mirror::AbstractMethod* method = instrumentation_frame.method_;
570 if (is_deoptimization) {
571 if (kVerboseInstrumentation) {
572 LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
573 }
574 } else {
575 if (kVerboseInstrumentation) {
576 LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
577 }
578
579 // Notify listeners of method unwind.
580 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
581 // return_pc.
582 uint32_t dex_pc = DexFile::kDexNoIndex;
583 MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
584 }
585}
586
587std::string InstrumentationStackFrame::Dump() const {
588 std::ostringstream os;
589 os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
590 << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
591 return os.str();
592}
593
594} // namespace instrumentation
jeffhao725a9572012-11-13 18:20:12 -0800595} // namespace art