blob: 9d051694b9d3754843547e2912bf7ab2d23581ca [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 Rogersef7d42f2014-01-06 12:55:46 -080021#include "atomic.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"
Sebastien Hertz138dbfc2013-12-04 18:15:25 +010026#include "interpreter/interpreter.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070027#include "mirror/art_method-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080028#include "mirror/class-inl.h"
29#include "mirror/dex_cache.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080030#include "mirror/object_array-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070031#include "mirror/object-inl.h"
Ian Rogers62d6c772013-02-27 08:32:07 -080032#include "nth_caller_visitor.h"
Ian Rogersc928de92013-02-27 14:30:44 -080033#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers166db042013-07-26 12:05:57 -070034#include "entrypoints/quick/quick_entrypoints.h"
jeffhao725a9572012-11-13 18:20:12 -080035#endif
36#include "object_utils.h"
37#include "os.h"
38#include "scoped_thread_state_change.h"
39#include "thread.h"
40#include "thread_list.h"
jeffhao725a9572012-11-13 18:20:12 -080041
42namespace art {
Ian Rogersfa824272013-11-05 16:12:57 -080043
44extern void SetQuickAllocEntryPointsInstrumented(bool instrumented);
45
Ian Rogers62d6c772013-02-27 08:32:07 -080046namespace instrumentation {
jeffhao725a9572012-11-13 18:20:12 -080047
Sebastien Hertz5bfd5c92013-11-15 11:36:07 +010048const bool kVerboseInstrumentation = false;
49
Ian Rogers816432e2013-09-06 15:47:45 -070050// Do we want to deoptimize for method entry and exit listeners or just try to intercept
51// invocations? Deoptimization forces all code to run in the interpreter and considerably hurts the
52// application's performance.
Ian Rogers7b6da362013-09-11 09:29:40 -070053static constexpr bool kDeoptimizeForAccurateMethodEntryExitListeners = false;
Ian Rogers816432e2013-09-06 15:47:45 -070054
Ian Rogers62d6c772013-02-27 08:32:07 -080055static bool InstallStubsClassVisitor(mirror::Class* klass, void* arg)
jeffhao725a9572012-11-13 18:20:12 -080056 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -080057 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
58 return instrumentation->InstallStubsForClass(klass);
59}
60
61bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
Sebastien Hertz138dbfc2013-12-04 18:15:25 +010062 for (size_t i = 0, e = klass->NumDirectMethods(); i < e; i++) {
63 InstallStubsForMethod(klass->GetDirectMethod(i));
jeffhao725a9572012-11-13 18:20:12 -080064 }
Sebastien Hertz138dbfc2013-12-04 18:15:25 +010065 for (size_t i = 0, e = klass->NumVirtualMethods(); i < e; i++) {
66 InstallStubsForMethod(klass->GetVirtualMethod(i));
jeffhao725a9572012-11-13 18:20:12 -080067 }
68 return true;
69}
70
Ian Rogersef7d42f2014-01-06 12:55:46 -080071static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code,
72 const void* portable_code, bool have_portable_code)
73 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
74 method->SetEntryPointFromPortableCompiledCode(portable_code);
75 method->SetEntryPointFromQuickCompiledCode(quick_code);
76 bool portable_enabled = method->IsPortableCompiled();
77 if (have_portable_code && !portable_enabled) {
78 method->SetIsPortableCompiled();
79 } else if (portable_enabled) {
80 method->ClearIsPortableCompiled();
81 }
Sebastien Hertz138dbfc2013-12-04 18:15:25 +010082 if (!method->IsResolutionMethod()) {
Ian Rogersef7d42f2014-01-06 12:55:46 -080083 if (quick_code == GetQuickToInterpreterBridge()) {
84 DCHECK(portable_code == GetPortableToInterpreterBridge());
85 DCHECK(!method->IsNative()) << PrettyMethod(method);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +010086 method->SetEntryPointFromInterpreter(art::interpreter::artInterpreterToInterpreterBridge);
87 } else {
88 method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
89 }
90 }
91}
92
93void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) {
94 if (method->IsAbstract() || method->IsProxyMethod()) {
95 // Do not change stubs for these methods.
96 return;
97 }
Ian Rogersef7d42f2014-01-06 12:55:46 -080098 const void* new_portable_code;
99 const void* new_quick_code;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100100 bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
101 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
102 bool is_class_initialized = method->GetDeclaringClass()->IsInitialized();
Ian Rogersef7d42f2014-01-06 12:55:46 -0800103 bool have_portable_code = false;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100104 if (uninstall) {
105 if ((forced_interpret_only_ || IsDeoptimized(method)) && !method->IsNative()) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800106 new_portable_code = GetPortableToInterpreterBridge();
107 new_quick_code = GetQuickToInterpreterBridge();
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100108 } else if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800109 new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
110 new_quick_code = class_linker->GetQuickOatCodeFor(method);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100111 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800112 new_portable_code = GetPortableResolutionTrampoline(class_linker);
113 new_quick_code = GetQuickResolutionTrampoline(class_linker);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100114 }
115 } else { // !uninstall
116 if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800117 new_portable_code = GetPortableToInterpreterBridge();
118 new_quick_code = GetQuickToInterpreterBridge();
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100119 } else {
120 // Do not overwrite resolution trampoline. When the trampoline initializes the method's
121 // class, all its static methods code will be set to the instrumentation entry point.
122 // For more details, see ClassLinker::FixupStaticTrampolines.
123 if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
124 // Do not overwrite interpreter to prevent from posting method entry/exit events twice.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800125 new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
126 new_quick_code = class_linker->GetQuickOatCodeFor(method);
127 if (entry_exit_stubs_installed_ && new_quick_code != GetQuickToInterpreterBridge()) {
128 DCHECK(new_portable_code != GetPortableToInterpreterBridge());
129 new_portable_code = GetPortableToInterpreterBridge();
130 new_quick_code = GetQuickInstrumentationEntryPoint();
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100131 }
132 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800133 new_portable_code = GetPortableResolutionTrampoline(class_linker);
134 new_quick_code = GetQuickResolutionTrampoline(class_linker);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100135 }
136 }
137 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800138 UpdateEntrypoints(method, new_quick_code, new_portable_code, have_portable_code);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100139}
140
Ian Rogers62d6c772013-02-27 08:32:07 -0800141// Places the instrumentation exit pc as the return PC for every quick frame. This also allows
142// deoptimization of quick frames to interpreter frames.
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100143// Since we may already have done this previously, we need to push new instrumentation frame before
144// existing instrumentation frames.
Ian Rogers62d6c772013-02-27 08:32:07 -0800145static void InstrumentationInstallStack(Thread* thread, void* arg)
Ian Rogers306057f2012-11-26 12:45:53 -0800146 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
147 struct InstallStackVisitor : public StackVisitor {
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100148 InstallStackVisitor(Thread* thread, Context* context, uintptr_t instrumentation_exit_pc)
Ian Rogers62d6c772013-02-27 08:32:07 -0800149 : StackVisitor(thread, context), instrumentation_stack_(thread->GetInstrumentationStack()),
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100150 existing_instrumentation_frames_count_(instrumentation_stack_->size()),
151 instrumentation_exit_pc_(instrumentation_exit_pc),
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100152 reached_existing_instrumentation_frames_(false), instrumentation_stack_depth_(0),
153 last_return_pc_(0) {
154 }
jeffhao725a9572012-11-13 18:20:12 -0800155
Ian Rogers306057f2012-11-26 12:45:53 -0800156 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Brian Carlstromea46f952013-07-30 01:26:50 -0700157 mirror::ArtMethod* m = GetMethod();
Ian Rogers306057f2012-11-26 12:45:53 -0800158 if (GetCurrentQuickFrame() == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800159 if (kVerboseInstrumentation) {
160 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId()
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100161 << " Method=" << PrettyMethod(m);
Ian Rogers62d6c772013-02-27 08:32:07 -0800162 }
Ian Rogers306057f2012-11-26 12:45:53 -0800163 return true; // Ignore shadow frames.
164 }
Ian Rogers306057f2012-11-26 12:45:53 -0800165 if (m == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800166 if (kVerboseInstrumentation) {
167 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
168 }
169 last_return_pc_ = 0;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700170 return true; // Ignore upcalls.
Ian Rogers306057f2012-11-26 12:45:53 -0800171 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800172 if (m->IsRuntimeMethod()) {
173 if (kVerboseInstrumentation) {
174 LOG(INFO) << " Skipping runtime method. Frame " << GetFrameId();
175 }
176 last_return_pc_ = GetReturnPc();
Ian Rogers306057f2012-11-26 12:45:53 -0800177 return true; // Ignore unresolved methods since they will be instrumented after resolution.
178 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800179 if (kVerboseInstrumentation) {
180 LOG(INFO) << " Installing exit stub in " << DescribeLocation();
181 }
182 uintptr_t return_pc = GetReturnPc();
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100183 if (return_pc == instrumentation_exit_pc_) {
184 // We've reached a frame which has already been installed with instrumentation exit stub.
185 // We should have already installed instrumentation on previous frames.
186 reached_existing_instrumentation_frames_ = true;
187
188 CHECK_LT(instrumentation_stack_depth_, instrumentation_stack_->size());
189 const InstrumentationStackFrame& frame = instrumentation_stack_->at(instrumentation_stack_depth_);
190 CHECK_EQ(m, frame.method_) << "Expected " << PrettyMethod(m)
191 << ", Found " << PrettyMethod(frame.method_);
192 return_pc = frame.return_pc_;
193 if (kVerboseInstrumentation) {
194 LOG(INFO) << "Ignoring already instrumented " << frame.Dump();
195 }
196 } else {
197 CHECK_NE(return_pc, 0U);
198 CHECK(!reached_existing_instrumentation_frames_);
199 InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, return_pc, GetFrameId(),
200 false);
201 if (kVerboseInstrumentation) {
202 LOG(INFO) << "Pushing frame " << instrumentation_frame.Dump();
203 }
204
205 // Insert frame before old ones so we do not corrupt the instrumentation stack.
206 auto it = instrumentation_stack_->end() - existing_instrumentation_frames_count_;
207 instrumentation_stack_->insert(it, instrumentation_frame);
208 SetReturnPc(instrumentation_exit_pc_);
Ian Rogers62d6c772013-02-27 08:32:07 -0800209 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800210 dex_pcs_.push_back(m->ToDexPc(last_return_pc_));
Ian Rogers62d6c772013-02-27 08:32:07 -0800211 last_return_pc_ = return_pc;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100212 ++instrumentation_stack_depth_;
Ian Rogers306057f2012-11-26 12:45:53 -0800213 return true; // Continue.
214 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800215 std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100216 const size_t existing_instrumentation_frames_count_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800217 std::vector<uint32_t> dex_pcs_;
Ian Rogers306057f2012-11-26 12:45:53 -0800218 const uintptr_t instrumentation_exit_pc_;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100219 bool reached_existing_instrumentation_frames_;
220 size_t instrumentation_stack_depth_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800221 uintptr_t last_return_pc_;
Ian Rogers306057f2012-11-26 12:45:53 -0800222 };
Ian Rogers62d6c772013-02-27 08:32:07 -0800223 if (kVerboseInstrumentation) {
224 std::string thread_name;
225 thread->GetThreadName(thread_name);
226 LOG(INFO) << "Installing exit stubs in " << thread_name;
Ian Rogers306057f2012-11-26 12:45:53 -0800227 }
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100228
229 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
Ian Rogers62d6c772013-02-27 08:32:07 -0800230 UniquePtr<Context> context(Context::Create());
Ian Rogers848871b2013-08-05 10:56:33 -0700231 uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100232 InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800233 visitor.WalkStack(true);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100234 CHECK_EQ(visitor.dex_pcs_.size(), thread->GetInstrumentationStack()->size());
Ian Rogers62d6c772013-02-27 08:32:07 -0800235
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100236 if (!instrumentation->ShouldNotifyMethodEnterExitEvents()) {
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100237 // Create method enter events for all methods currently on the thread's stack. We only do this
238 // if no debugger is attached to prevent from posting events twice.
239 typedef std::deque<InstrumentationStackFrame>::const_reverse_iterator It;
240 for (It it = thread->GetInstrumentationStack()->rbegin(),
241 end = thread->GetInstrumentationStack()->rend(); it != end; ++it) {
242 mirror::Object* this_object = (*it).this_object_;
243 mirror::ArtMethod* method = (*it).method_;
244 uint32_t dex_pc = visitor.dex_pcs_.back();
245 visitor.dex_pcs_.pop_back();
246 instrumentation->MethodEnterEvent(thread, this_object, method, dex_pc);
247 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800248 }
249 thread->VerifyStack();
Ian Rogers306057f2012-11-26 12:45:53 -0800250}
251
Ian Rogers62d6c772013-02-27 08:32:07 -0800252// Removes the instrumentation exit pc as the return PC for every quick frame.
253static void InstrumentationRestoreStack(Thread* thread, void* arg)
Ian Rogers306057f2012-11-26 12:45:53 -0800254 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
255 struct RestoreStackVisitor : public StackVisitor {
Ian Rogers62d6c772013-02-27 08:32:07 -0800256 RestoreStackVisitor(Thread* thread, uintptr_t instrumentation_exit_pc,
257 Instrumentation* instrumentation)
258 : StackVisitor(thread, NULL), thread_(thread),
259 instrumentation_exit_pc_(instrumentation_exit_pc),
260 instrumentation_(instrumentation),
261 instrumentation_stack_(thread->GetInstrumentationStack()),
262 frames_removed_(0) {}
Ian Rogers306057f2012-11-26 12:45:53 -0800263
264 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800265 if (instrumentation_stack_->size() == 0) {
jeffhao725a9572012-11-13 18:20:12 -0800266 return false; // Stop.
267 }
Brian Carlstromea46f952013-07-30 01:26:50 -0700268 mirror::ArtMethod* m = GetMethod();
Ian Rogers62d6c772013-02-27 08:32:07 -0800269 if (GetCurrentQuickFrame() == NULL) {
270 if (kVerboseInstrumentation) {
271 LOG(INFO) << " Ignoring a shadow frame. Frame " << GetFrameId() << " Method=" << PrettyMethod(m);
272 }
273 return true; // Ignore shadow frames.
274 }
Ian Rogers306057f2012-11-26 12:45:53 -0800275 if (m == NULL) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800276 if (kVerboseInstrumentation) {
277 LOG(INFO) << " Skipping upcall. Frame " << GetFrameId();
278 }
Ian Rogers306057f2012-11-26 12:45:53 -0800279 return true; // Ignore upcalls.
280 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800281 bool removed_stub = false;
282 // TODO: make this search more efficient?
Mathieu Chartier02e25112013-08-14 16:14:24 -0700283 for (InstrumentationStackFrame instrumentation_frame : *instrumentation_stack_) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800284 if (instrumentation_frame.frame_id_ == GetFrameId()) {
285 if (kVerboseInstrumentation) {
286 LOG(INFO) << " Removing exit stub in " << DescribeLocation();
287 }
Jeff Hao9a916d32013-06-27 18:45:37 -0700288 if (instrumentation_frame.interpreter_entry_) {
289 CHECK(m == Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
290 } else {
291 CHECK(m == instrumentation_frame.method_) << PrettyMethod(m);
292 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800293 SetReturnPc(instrumentation_frame.return_pc_);
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100294 if (!instrumentation_->ShouldNotifyMethodEnterExitEvents()) {
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100295 // Create the method exit events. As the methods didn't really exit the result is 0.
296 // We only do this if no debugger is attached to prevent from posting events twice.
297 instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m,
298 GetDexPc(), JValue());
299 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800300 frames_removed_++;
301 removed_stub = true;
302 break;
303 }
304 }
305 if (!removed_stub) {
306 if (kVerboseInstrumentation) {
307 LOG(INFO) << " No exit stub in " << DescribeLocation();
Ian Rogers306057f2012-11-26 12:45:53 -0800308 }
jeffhao725a9572012-11-13 18:20:12 -0800309 }
310 return true; // Continue.
311 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800312 Thread* const thread_;
Ian Rogers306057f2012-11-26 12:45:53 -0800313 const uintptr_t instrumentation_exit_pc_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800314 Instrumentation* const instrumentation_;
315 std::deque<instrumentation::InstrumentationStackFrame>* const instrumentation_stack_;
316 size_t frames_removed_;
jeffhao725a9572012-11-13 18:20:12 -0800317 };
Ian Rogers62d6c772013-02-27 08:32:07 -0800318 if (kVerboseInstrumentation) {
319 std::string thread_name;
320 thread->GetThreadName(thread_name);
321 LOG(INFO) << "Removing exit stubs in " << thread_name;
322 }
323 std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
324 if (stack->size() > 0) {
325 Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
Ian Rogers848871b2013-08-05 10:56:33 -0700326 uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
Ian Rogers62d6c772013-02-27 08:32:07 -0800327 RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
328 visitor.WalkStack(true);
329 CHECK_EQ(visitor.frames_removed_, stack->size());
330 while (stack->size() > 0) {
331 stack->pop_front();
332 }
jeffhao725a9572012-11-13 18:20:12 -0800333 }
334}
335
Ian Rogers62d6c772013-02-27 08:32:07 -0800336void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t events) {
337 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
Ian Rogers62d6c772013-02-27 08:32:07 -0800338 if ((events & kMethodEntered) != 0) {
339 method_entry_listeners_.push_back(listener);
Ian Rogers62d6c772013-02-27 08:32:07 -0800340 have_method_entry_listeners_ = true;
341 }
342 if ((events & kMethodExited) != 0) {
343 method_exit_listeners_.push_back(listener);
Ian Rogers62d6c772013-02-27 08:32:07 -0800344 have_method_exit_listeners_ = true;
345 }
346 if ((events & kMethodUnwind) != 0) {
347 method_unwind_listeners_.push_back(listener);
348 have_method_unwind_listeners_ = true;
349 }
350 if ((events & kDexPcMoved) != 0) {
351 dex_pc_listeners_.push_back(listener);
Ian Rogers62d6c772013-02-27 08:32:07 -0800352 have_dex_pc_listeners_ = true;
353 }
Jeff Hao14dd5a82013-04-11 10:23:36 -0700354 if ((events & kExceptionCaught) != 0) {
355 exception_caught_listeners_.push_back(listener);
356 have_exception_caught_listeners_ = true;
357 }
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200358 UpdateInterpreterHandlerTable();
jeffhao725a9572012-11-13 18:20:12 -0800359}
360
Ian Rogers62d6c772013-02-27 08:32:07 -0800361void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t events) {
362 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
Ian Rogers62d6c772013-02-27 08:32:07 -0800363
364 if ((events & kMethodEntered) != 0) {
365 bool contains = std::find(method_entry_listeners_.begin(), method_entry_listeners_.end(),
366 listener) != method_entry_listeners_.end();
367 if (contains) {
368 method_entry_listeners_.remove(listener);
369 }
370 have_method_entry_listeners_ = method_entry_listeners_.size() > 0;
Ian Rogers62d6c772013-02-27 08:32:07 -0800371 }
372 if ((events & kMethodExited) != 0) {
373 bool contains = std::find(method_exit_listeners_.begin(), method_exit_listeners_.end(),
374 listener) != method_exit_listeners_.end();
375 if (contains) {
376 method_exit_listeners_.remove(listener);
377 }
378 have_method_exit_listeners_ = method_exit_listeners_.size() > 0;
Ian Rogers62d6c772013-02-27 08:32:07 -0800379 }
380 if ((events & kMethodUnwind) != 0) {
381 method_unwind_listeners_.remove(listener);
382 }
383 if ((events & kDexPcMoved) != 0) {
384 bool contains = std::find(dex_pc_listeners_.begin(), dex_pc_listeners_.end(),
385 listener) != dex_pc_listeners_.end();
386 if (contains) {
387 dex_pc_listeners_.remove(listener);
388 }
389 have_dex_pc_listeners_ = dex_pc_listeners_.size() > 0;
Ian Rogers62d6c772013-02-27 08:32:07 -0800390 }
Jeff Hao14dd5a82013-04-11 10:23:36 -0700391 if ((events & kExceptionCaught) != 0) {
392 exception_caught_listeners_.remove(listener);
393 have_exception_caught_listeners_ = exception_caught_listeners_.size() > 0;
394 }
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200395 UpdateInterpreterHandlerTable();
jeffhao725a9572012-11-13 18:20:12 -0800396}
397
Ian Rogers62d6c772013-02-27 08:32:07 -0800398void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter) {
399 interpret_only_ = require_interpreter || forced_interpret_only_;
400 // Compute what level of instrumentation is required and compare to current.
401 int desired_level, current_level;
402 if (require_interpreter) {
403 desired_level = 2;
404 } else if (require_entry_exit_stubs) {
405 desired_level = 1;
406 } else {
407 desired_level = 0;
408 }
409 if (interpreter_stubs_installed_) {
410 current_level = 2;
411 } else if (entry_exit_stubs_installed_) {
412 current_level = 1;
413 } else {
414 current_level = 0;
415 }
416 if (desired_level == current_level) {
417 // We're already set.
418 return;
419 }
420 Thread* self = Thread::Current();
421 Runtime* runtime = Runtime::Current();
422 Locks::thread_list_lock_->AssertNotHeld(self);
423 if (desired_level > 0) {
424 if (require_interpreter) {
425 interpreter_stubs_installed_ = true;
426 } else {
427 CHECK(require_entry_exit_stubs);
428 entry_exit_stubs_installed_ = true;
429 }
430 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
431 instrumentation_stubs_installed_ = true;
432 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
433 runtime->GetThreadList()->ForEach(InstrumentationInstallStack, this);
434 } else {
435 interpreter_stubs_installed_ = false;
436 entry_exit_stubs_installed_ = false;
437 runtime->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, this);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100438 // Restore stack only if there is no method currently deoptimized.
439 if (deoptimized_methods_.empty()) {
440 instrumentation_stubs_installed_ = false;
441 MutexLock mu(self, *Locks::thread_list_lock_);
442 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
443 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800444 }
jeffhao725a9572012-11-13 18:20:12 -0800445}
446
Ian Rogersfa824272013-11-05 16:12:57 -0800447static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
448 thread->ResetQuickAllocEntryPointsForThread();
449}
450
451void Instrumentation::InstrumentQuickAllocEntryPoints() {
452 // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
453 // should be guarded by a lock.
Ian Rogersb122a4b2013-11-19 18:00:50 -0800454 DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_.Load(), 0);
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800455 const bool enable_instrumentation =
Ian Rogersb122a4b2013-11-19 18:00:50 -0800456 quick_alloc_entry_points_instrumentation_counter_.FetchAndAdd(1) == 0;
Ian Rogersfa824272013-11-05 16:12:57 -0800457 if (enable_instrumentation) {
458 // Instrumentation wasn't enabled so enable it.
459 SetQuickAllocEntryPointsInstrumented(true);
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800460 ThreadList* tl = Runtime::Current()->GetThreadList();
461 tl->SuspendAll();
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800462 ResetQuickAllocEntryPoints();
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800463 tl->ResumeAll();
Ian Rogersfa824272013-11-05 16:12:57 -0800464 }
465}
466
467void Instrumentation::UninstrumentQuickAllocEntryPoints() {
468 // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
469 // should be guarded by a lock.
Ian Rogersb122a4b2013-11-19 18:00:50 -0800470 DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_.Load(), 0);
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800471 const bool disable_instrumentation =
Ian Rogersb122a4b2013-11-19 18:00:50 -0800472 quick_alloc_entry_points_instrumentation_counter_.FetchAndSub(1) == 1;
Ian Rogersfa824272013-11-05 16:12:57 -0800473 if (disable_instrumentation) {
474 SetQuickAllocEntryPointsInstrumented(false);
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800475 ThreadList* tl = Runtime::Current()->GetThreadList();
476 tl->SuspendAll();
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800477 ResetQuickAllocEntryPoints();
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800478 tl->ResumeAll();
Mathieu Chartiercbb2d202013-11-14 17:45:16 -0800479 }
480}
481
482void Instrumentation::ResetQuickAllocEntryPoints() {
483 Runtime* runtime = Runtime::Current();
484 if (runtime->IsStarted()) {
Mathieu Chartiere6da9af2013-12-16 11:54:42 -0800485 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
486 runtime->GetThreadList()->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
Ian Rogersfa824272013-11-05 16:12:57 -0800487 }
488}
489
Ian Rogersef7d42f2014-01-06 12:55:46 -0800490void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code,
491 const void* portable_code, bool have_portable_code) const {
492 const void* new_portable_code;
493 const void* new_quick_code;
494 bool new_have_portable_code;
Ian Rogers62d6c772013-02-27 08:32:07 -0800495 if (LIKELY(!instrumentation_stubs_installed_)) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800496 new_portable_code = portable_code;
497 new_quick_code = quick_code;
498 new_have_portable_code = have_portable_code;
Jeff Hao65d15d92013-07-16 16:39:33 -0700499 } else {
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100500 if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800501 new_portable_code = GetPortableToInterpreterBridge();
502 new_quick_code = GetQuickToInterpreterBridge();
503 new_have_portable_code = false;
504 } else if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker()) ||
505 quick_code == GetQuickToInterpreterBridge()) {
506 DCHECK((portable_code == GetPortableResolutionTrampoline(Runtime::Current()->GetClassLinker())) ||
507 (portable_code == GetPortableToInterpreterBridge()));
508 new_portable_code = portable_code;
509 new_quick_code = quick_code;
510 new_have_portable_code = have_portable_code;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100511 } else if (entry_exit_stubs_installed_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800512 new_quick_code = GetQuickInstrumentationEntryPoint();
513 new_portable_code = GetPortableToInterpreterBridge();
514 new_have_portable_code = false;
Jeff Hao65d15d92013-07-16 16:39:33 -0700515 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800516 new_portable_code = portable_code;
517 new_quick_code = quick_code;
518 new_have_portable_code = have_portable_code;
Jeff Hao65d15d92013-07-16 16:39:33 -0700519 }
Ian Rogers62d6c772013-02-27 08:32:07 -0800520 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800521 UpdateEntrypoints(method, new_quick_code, new_portable_code, new_have_portable_code);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100522}
523
524void Instrumentation::Deoptimize(mirror::ArtMethod* method) {
525 CHECK(!method->IsNative());
526 CHECK(!method->IsProxyMethod());
527 CHECK(!method->IsAbstract());
528
529 std::pair<std::set<mirror::ArtMethod*>::iterator, bool> pair = deoptimized_methods_.insert(method);
530 bool already_deoptimized = !pair.second;
531 CHECK(!already_deoptimized) << "Method " << PrettyMethod(method) << " is already deoptimized";
532
533 if (!interpreter_stubs_installed_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800534 UpdateEntrypoints(method, GetQuickToInterpreterBridge(), GetPortableToInterpreterBridge(),
535 false);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100536
537 // Install instrumentation exit stub and instrumentation frames. We may already have installed
538 // these previously so it will only cover the newly created frames.
539 instrumentation_stubs_installed_ = true;
540 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
541 Runtime::Current()->GetThreadList()->ForEach(InstrumentationInstallStack, this);
542 }
543}
544
545void Instrumentation::Undeoptimize(mirror::ArtMethod* method) {
546 CHECK(!method->IsNative());
547 CHECK(!method->IsProxyMethod());
548 CHECK(!method->IsAbstract());
549
550 auto it = deoptimized_methods_.find(method);
551 CHECK(it != deoptimized_methods_.end()) << "Method " << PrettyMethod(method) << " is not deoptimized";
552 deoptimized_methods_.erase(it);
553
554 // Restore code and possibly stack only if we did not deoptimize everything.
555 if (!interpreter_stubs_installed_) {
556 // Restore its code or resolution trampoline.
557 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersef7d42f2014-01-06 12:55:46 -0800558 if (method->IsStatic() && !method->IsConstructor() &&
559 !method->GetDeclaringClass()->IsInitialized()) {
560 UpdateEntrypoints(method, GetQuickResolutionTrampoline(class_linker),
561 GetPortableResolutionTrampoline(class_linker), false);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100562 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800563 bool have_portable_code = false;
564 const void* quick_code = class_linker->GetQuickOatCodeFor(method);
565 const void* portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
566 UpdateEntrypoints(method, quick_code, portable_code, have_portable_code);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100567 }
568
569 // If there is no deoptimized method left, we can restore the stack of each thread.
570 if (deoptimized_methods_.empty()) {
571 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
572 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
573 instrumentation_stubs_installed_ = false;
574 }
575 }
576}
577
578bool Instrumentation::IsDeoptimized(mirror::ArtMethod* method) const {
579 DCHECK(method != nullptr);
580 return deoptimized_methods_.count(method);
581}
582
583void Instrumentation::EnableDeoptimization() {
584 CHECK(deoptimized_methods_.empty());
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100585 CHECK_EQ(deoptimization_enabled_, false);
586 deoptimization_enabled_ = true;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100587}
588
589void Instrumentation::DisableDeoptimization() {
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100590 CHECK_EQ(deoptimization_enabled_, true);
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100591 // If we deoptimized everything, undo it.
592 if (interpreter_stubs_installed_) {
593 UndeoptimizeEverything();
594 }
595 // Undeoptimized selected methods.
596 while (!deoptimized_methods_.empty()) {
597 auto it_begin = deoptimized_methods_.begin();
598 Undeoptimize(*it_begin);
599 }
600 CHECK(deoptimized_methods_.empty());
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100601 deoptimization_enabled_ = false;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100602}
603
Sebastien Hertz11d40c22014-02-19 18:00:17 +0100604// Indicates if instrumentation should notify method enter/exit events to the listeners.
605bool Instrumentation::ShouldNotifyMethodEnterExitEvents() const {
606 return deoptimization_enabled_ || interpreter_stubs_installed_;
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100607}
608
609void Instrumentation::DeoptimizeEverything() {
610 CHECK(!interpreter_stubs_installed_);
611 ConfigureStubs(false, true);
612}
613
614void Instrumentation::UndeoptimizeEverything() {
615 CHECK(interpreter_stubs_installed_);
616 ConfigureStubs(false, false);
617}
618
619void Instrumentation::EnableMethodTracing() {
620 bool require_interpreter = kDeoptimizeForAccurateMethodEntryExitListeners;
621 ConfigureStubs(!require_interpreter, require_interpreter);
622}
623
624void Instrumentation::DisableMethodTracing() {
625 ConfigureStubs(false, false);
jeffhao725a9572012-11-13 18:20:12 -0800626}
627
Ian Rogersef7d42f2014-01-06 12:55:46 -0800628const void* Instrumentation::GetQuickCodeFor(mirror::ArtMethod* method) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800629 Runtime* runtime = Runtime::Current();
630 if (LIKELY(!instrumentation_stubs_installed_)) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800631 const void* code = method->GetEntryPointFromQuickCompiledCode();
Ian Rogers62d6c772013-02-27 08:32:07 -0800632 DCHECK(code != NULL);
Ian Rogers848871b2013-08-05 10:56:33 -0700633 if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker()) &&
634 code != GetQuickToInterpreterBridge())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800635 return code;
636 }
637 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800638 return runtime->GetClassLinker()->GetQuickOatCodeFor(method);
jeffhao725a9572012-11-13 18:20:12 -0800639}
640
Ian Rogers62d6c772013-02-27 08:32:07 -0800641void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800642 mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800643 uint32_t dex_pc) const {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700644 auto it = method_entry_listeners_.begin();
Jeff Hao65d15d92013-07-16 16:39:33 -0700645 bool is_end = (it == method_entry_listeners_.end());
646 // Implemented this way to prevent problems caused by modification of the list while iterating.
647 while (!is_end) {
648 InstrumentationListener* cur = *it;
649 ++it;
650 is_end = (it == method_entry_listeners_.end());
651 cur->MethodEntered(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800652 }
653}
654
655void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800656 mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800657 uint32_t dex_pc, const JValue& return_value) const {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700658 auto it = method_exit_listeners_.begin();
Jeff Hao65d15d92013-07-16 16:39:33 -0700659 bool is_end = (it == method_exit_listeners_.end());
660 // Implemented this way to prevent problems caused by modification of the list while iterating.
661 while (!is_end) {
662 InstrumentationListener* cur = *it;
663 ++it;
664 is_end = (it == method_exit_listeners_.end());
665 cur->MethodExited(thread, this_object, method, dex_pc, return_value);
Ian Rogers62d6c772013-02-27 08:32:07 -0800666 }
667}
668
669void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800670 mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800671 uint32_t dex_pc) const {
672 if (have_method_unwind_listeners_) {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700673 for (InstrumentationListener* listener : method_unwind_listeners_) {
Sebastien Hertz51db44a2013-11-19 10:00:29 +0100674 listener->MethodUnwind(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800675 }
676 }
677}
678
679void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800680 mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800681 uint32_t dex_pc) const {
682 // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an
683 // action where it can remove itself as a listener and break the iterator. The copy only works
684 // around the problem and in general we may have to move to something like reference counting to
685 // ensure listeners are deleted correctly.
686 std::list<InstrumentationListener*> copy(dex_pc_listeners_);
Mathieu Chartier02e25112013-08-14 16:14:24 -0700687 for (InstrumentationListener* listener : copy) {
688 listener->DexPcMoved(thread, this_object, method, dex_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800689 }
690}
691
692void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
Brian Carlstromea46f952013-07-30 01:26:50 -0700693 mirror::ArtMethod* catch_method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800694 uint32_t catch_dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200695 mirror::Throwable* exception_object) const {
Ian Rogers62d6c772013-02-27 08:32:07 -0800696 if (have_exception_caught_listeners_) {
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700697 DCHECK_EQ(thread->GetException(NULL), exception_object);
698 thread->ClearException();
Mathieu Chartier02e25112013-08-14 16:14:24 -0700699 for (InstrumentationListener* listener : exception_caught_listeners_) {
700 listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800701 }
Jeff Haoc0bd4da2013-04-11 15:52:28 -0700702 thread->SetException(throw_location, exception_object);
Ian Rogers62d6c772013-02-27 08:32:07 -0800703 }
704}
705
706static void CheckStackDepth(Thread* self, const InstrumentationStackFrame& instrumentation_frame,
707 int delta)
708 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
709 size_t frame_id = StackVisitor::ComputeNumFrames(self) + delta;
710 if (frame_id != instrumentation_frame.frame_id_) {
711 LOG(ERROR) << "Expected frame_id=" << frame_id << " but found "
712 << instrumentation_frame.frame_id_;
713 StackVisitor::DescribeStack(self);
714 CHECK_EQ(frame_id, instrumentation_frame.frame_id_);
715 }
716}
717
718void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700719 mirror::ArtMethod* method,
Jeff Hao9a916d32013-06-27 18:45:37 -0700720 uintptr_t lr, bool interpreter_entry) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800721 // We have a callee-save frame meaning this value is guaranteed to never be 0.
722 size_t frame_id = StackVisitor::ComputeNumFrames(self);
723 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
724 if (kVerboseInstrumentation) {
Brian Carlstrom2d888622013-07-18 17:02:00 -0700725 LOG(INFO) << "Entering " << PrettyMethod(method) << " from PC " << reinterpret_cast<void*>(lr);
Ian Rogers62d6c772013-02-27 08:32:07 -0800726 }
727 instrumentation::InstrumentationStackFrame instrumentation_frame(this_object, method, lr,
Jeff Hao9a916d32013-06-27 18:45:37 -0700728 frame_id, interpreter_entry);
Ian Rogers62d6c772013-02-27 08:32:07 -0800729 stack->push_front(instrumentation_frame);
730
731 MethodEnterEvent(self, this_object, method, 0);
732}
733
734uint64_t Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc,
735 uint64_t gpr_result, uint64_t fpr_result) {
736 // Do the pop.
737 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
738 CHECK_GT(stack->size(), 0U);
739 InstrumentationStackFrame instrumentation_frame = stack->front();
740 stack->pop_front();
741
742 // Set return PC and check the sanity of the stack.
743 *return_pc = instrumentation_frame.return_pc_;
744 CheckStackDepth(self, instrumentation_frame, 0);
745
Brian Carlstromea46f952013-07-30 01:26:50 -0700746 mirror::ArtMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800747 char return_shorty = MethodHelper(method).GetShorty()[0];
748 JValue return_value;
749 if (return_shorty == 'V') {
750 return_value.SetJ(0);
751 } else if (return_shorty == 'F' || return_shorty == 'D') {
752 return_value.SetJ(fpr_result);
753 } else {
754 return_value.SetJ(gpr_result);
755 }
756 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
757 // return_pc.
758 uint32_t dex_pc = DexFile::kDexNoIndex;
759 mirror::Object* this_object = instrumentation_frame.this_object_;
760 MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value);
jeffhao725a9572012-11-13 18:20:12 -0800761
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100762 // Deoptimize if the caller needs to continue execution in the interpreter. Do nothing if we get
763 // back to an upcall.
764 NthCallerVisitor visitor(self, 1, true);
765 visitor.WalkStack(true);
766 bool deoptimize = (visitor.caller != NULL) &&
767 (interpreter_stubs_installed_ || IsDeoptimized(visitor.caller));
768 if (deoptimize && kVerboseInstrumentation) {
769 LOG(INFO) << "Deoptimizing into " << PrettyMethod(visitor.caller);
Ian Rogers62d6c772013-02-27 08:32:07 -0800770 }
771 if (deoptimize) {
772 if (kVerboseInstrumentation) {
773 LOG(INFO) << "Deoptimizing from " << PrettyMethod(method)
Sebastien Hertz138dbfc2013-12-04 18:15:25 +0100774 << " result is " << std::hex << return_value.GetJ();
Ian Rogers62d6c772013-02-27 08:32:07 -0800775 }
776 self->SetDeoptimizationReturnValue(return_value);
Ian Rogers848871b2013-08-05 10:56:33 -0700777 return static_cast<uint64_t>(GetQuickDeoptimizationEntryPoint()) |
Ian Rogers62d6c772013-02-27 08:32:07 -0800778 (static_cast<uint64_t>(*return_pc) << 32);
779 } else {
780 if (kVerboseInstrumentation) {
Brian Carlstrom2d888622013-07-18 17:02:00 -0700781 LOG(INFO) << "Returning from " << PrettyMethod(method)
782 << " to PC " << reinterpret_cast<void*>(*return_pc);
Ian Rogers62d6c772013-02-27 08:32:07 -0800783 }
784 return *return_pc;
785 }
jeffhao725a9572012-11-13 18:20:12 -0800786}
787
Ian Rogers62d6c772013-02-27 08:32:07 -0800788void Instrumentation::PopMethodForUnwind(Thread* self, bool is_deoptimization) const {
789 // Do the pop.
790 std::deque<instrumentation::InstrumentationStackFrame>* stack = self->GetInstrumentationStack();
791 CHECK_GT(stack->size(), 0U);
792 InstrumentationStackFrame instrumentation_frame = stack->front();
793 // TODO: bring back CheckStackDepth(self, instrumentation_frame, 2);
794 stack->pop_front();
795
Brian Carlstromea46f952013-07-30 01:26:50 -0700796 mirror::ArtMethod* method = instrumentation_frame.method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800797 if (is_deoptimization) {
798 if (kVerboseInstrumentation) {
799 LOG(INFO) << "Popping for deoptimization " << PrettyMethod(method);
800 }
801 } else {
802 if (kVerboseInstrumentation) {
803 LOG(INFO) << "Popping for unwind " << PrettyMethod(method);
804 }
805
806 // Notify listeners of method unwind.
807 // TODO: improve the dex pc information here, requires knowledge of current PC as opposed to
808 // return_pc.
809 uint32_t dex_pc = DexFile::kDexNoIndex;
810 MethodUnwindEvent(self, instrumentation_frame.this_object_, method, dex_pc);
811 }
812}
813
814std::string InstrumentationStackFrame::Dump() const {
815 std::ostringstream os;
816 os << "Frame " << frame_id_ << " " << PrettyMethod(method_) << ":"
817 << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_);
818 return os.str();
819}
820
821} // namespace instrumentation
jeffhao725a9572012-11-13 18:20:12 -0800822} // namespace art