blob: 6bfc2d7e3dd1ced38976668f736bdb28617333cf [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
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_INSTRUMENTATION_H_
18#define ART_RUNTIME_INSTRUMENTATION_H_
jeffhao725a9572012-11-13 18:20:12 -080019
Elliott Hughes76160052012-12-12 16:31:20 -080020#include "base/macros.h"
Ian Rogers62d6c772013-02-27 08:32:07 -080021#include "locks.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080022
23#include <stdint.h>
Ian Rogers62d6c772013-02-27 08:32:07 -080024#include <list>
jeffhao725a9572012-11-13 18:20:12 -080025
26namespace art {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080027namespace mirror {
Brian Carlstromea46f952013-07-30 01:26:50 -070028 class ArtMethod;
29 class Class;
30 class Object;
31 class Throwable;
Ian Rogers62d6c772013-02-27 08:32:07 -080032} // namespace mirror
33union JValue;
jeffhao725a9572012-11-13 18:20:12 -080034class Thread;
Ian Rogers62d6c772013-02-27 08:32:07 -080035class ThrowLocation;
jeffhao725a9572012-11-13 18:20:12 -080036
Ian Rogers62d6c772013-02-27 08:32:07 -080037namespace instrumentation {
jeffhao725a9572012-11-13 18:20:12 -080038
Sebastien Hertzee1997a2013-09-19 14:47:09 +020039// Interpreter handler tables.
40enum InterpreterHandlerTable {
41 kMainHandlerTable = 0, // Main handler table: no suspend check, no instrumentation.
42 kAlternativeHandlerTable = 1, // Alternative handler table: suspend check and/or instrumentation
43 // enabled.
44 kNumHandlerTables
45};
46
Ian Rogers62d6c772013-02-27 08:32:07 -080047// Instrumentation event listener API. Registered listeners will get the appropriate call back for
48// the events they are listening for. The call backs supply the thread, method and dex_pc the event
49// occurred upon. The thread may or may not be Thread::Current().
50struct InstrumentationListener {
51 InstrumentationListener() {}
52 virtual ~InstrumentationListener() {}
53
54 // Call-back for when a method is entered.
55 virtual void MethodEntered(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -070056 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -080057 uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
58
59 // Call-back for when a method is exited.
60 // TODO: its likely passing the return value would be useful, however, we may need to get and
61 // parse the shorty to determine what kind of register holds the result.
62 virtual void MethodExited(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -070063 const mirror::ArtMethod* method, uint32_t dex_pc,
Ian Rogers62d6c772013-02-27 08:32:07 -080064 const JValue& return_value)
65 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
66
67 // Call-back for when a method is popped due to an exception throw. A method will either cause a
68 // MethodExited call-back or a MethodUnwind call-back when its activation is removed.
Sebastien Hertz51db44a2013-11-19 10:00:29 +010069 virtual void MethodUnwind(Thread* thread, mirror::Object* this_object,
70 const mirror::ArtMethod* method, uint32_t dex_pc)
71 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
Ian Rogers62d6c772013-02-27 08:32:07 -080072
73 // Call-back for when the dex pc moves in a method.
74 virtual void DexPcMoved(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -070075 const mirror::ArtMethod* method, uint32_t new_dex_pc)
Ian Rogers62d6c772013-02-27 08:32:07 -080076 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
77
78 // Call-back when an exception is caught.
79 virtual void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location,
Brian Carlstromea46f952013-07-30 01:26:50 -070080 mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
Ian Rogers62d6c772013-02-27 08:32:07 -080081 mirror::Throwable* exception_object)
82 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
jeffhao725a9572012-11-13 18:20:12 -080083};
84
Ian Rogers62d6c772013-02-27 08:32:07 -080085// Instrumentation is a catch-all for when extra information is required from the runtime. The
86// typical use for instrumentation is for profiling and debugging. Instrumentation may add stubs
87// to method entry and exit, it may also force execution to be switched to the interpreter and
88// trigger deoptimization.
jeffhao725a9572012-11-13 18:20:12 -080089class Instrumentation {
90 public:
Ian Rogers62d6c772013-02-27 08:32:07 -080091 enum InstrumentationEvent {
92 kMethodEntered = 1,
93 kMethodExited = 2,
94 kMethodUnwind = 4,
95 kDexPcMoved = 8,
96 kExceptionCaught = 16
97 };
jeffhao725a9572012-11-13 18:20:12 -080098
Ian Rogers62d6c772013-02-27 08:32:07 -080099 Instrumentation() :
100 instrumentation_stubs_installed_(false), entry_exit_stubs_installed_(false),
101 interpreter_stubs_installed_(false),
102 interpret_only_(false), forced_interpret_only_(false),
103 have_method_entry_listeners_(false), have_method_exit_listeners_(false),
104 have_method_unwind_listeners_(false), have_dex_pc_listeners_(false),
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200105 have_exception_caught_listeners_(false),
Ian Rogersfa824272013-11-05 16:12:57 -0800106 interpreter_handler_table_(kMainHandlerTable),
107 quick_alloc_entry_points_instrumentation_counter_(0) {}
jeffhao725a9572012-11-13 18:20:12 -0800108
Ian Rogers62d6c772013-02-27 08:32:07 -0800109 // Add a listener to be notified of the masked together sent of instrumentation events. This
110 // suspend the runtime to install stubs. You are expected to hold the mutator lock as a proxy
111 // for saying you should have suspended all threads (installing stubs while threads are running
112 // will break).
113 void AddListener(InstrumentationListener* listener, uint32_t events)
114 EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
115 LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::classlinker_classes_lock_);
jeffhao725a9572012-11-13 18:20:12 -0800116
Ian Rogers62d6c772013-02-27 08:32:07 -0800117 // Removes a listener possibly removing instrumentation stubs.
118 void RemoveListener(InstrumentationListener* listener, uint32_t events)
119 EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
120 LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::classlinker_classes_lock_);
jeffhao725a9572012-11-13 18:20:12 -0800121
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200122 InterpreterHandlerTable GetInterpreterHandlerTable() const {
123 return interpreter_handler_table_;
124 }
125
Ian Rogersfa824272013-11-05 16:12:57 -0800126 void InstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_);
127 void UninstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_);
128
Ian Rogers62d6c772013-02-27 08:32:07 -0800129 // Update the code of a method respecting any installed stubs.
Brian Carlstromea46f952013-07-30 01:26:50 -0700130 void UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const;
Ian Rogers62d6c772013-02-27 08:32:07 -0800131
132 // Get the quick code for the given method. More efficient than asking the class linker as it
133 // will short-cut to GetCode if instrumentation and static method resolution stubs aren't
134 // installed.
Brian Carlstromea46f952013-07-30 01:26:50 -0700135 const void* GetQuickCodeFor(const mirror::ArtMethod* method) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800136 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
137
138 void ForceInterpretOnly() {
139 interpret_only_ = true;
140 forced_interpret_only_ = true;
141 }
142
Brian Carlstromea46f952013-07-30 01:26:50 -0700143 // Called by ArtMethod::Invoke to determine dispatch mechanism.
Ian Rogers62d6c772013-02-27 08:32:07 -0800144 bool InterpretOnly() const {
145 return interpret_only_;
146 }
147
148 bool ShouldPortableCodeDeoptimize() const {
149 return instrumentation_stubs_installed_;
150 }
151
152 bool AreExitStubsInstalled() const {
153 return instrumentation_stubs_installed_;
154 }
155
Sebastien Hertz74109f62013-06-07 17:40:09 +0200156 bool HasMethodEntryListeners() const {
157 return have_method_entry_listeners_;
158 }
159
160 bool HasMethodExitListeners() const {
161 return have_method_exit_listeners_;
162 }
163
164 bool HasDexPcListeners() const {
165 return have_dex_pc_listeners_;
166 }
167
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200168 bool IsActive() const {
169 return have_dex_pc_listeners_ || have_method_entry_listeners_ || have_method_exit_listeners_ ||
170 have_exception_caught_listeners_ || have_method_unwind_listeners_;
171 }
172
Ian Rogers62d6c772013-02-27 08:32:07 -0800173 // Inform listeners that a method has been entered. A dex PC is provided as we may install
174 // listeners into executing code and get method enter events for methods already on the stack.
175 void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700176 const mirror::ArtMethod* method, uint32_t dex_pc) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800177 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Sebastien Hertz74109f62013-06-07 17:40:09 +0200178 if (UNLIKELY(HasMethodEntryListeners())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800179 MethodEnterEventImpl(thread, this_object, method, dex_pc);
180 }
181 }
182
183 // Inform listeners that a method has been exited.
184 void MethodExitEvent(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700185 const mirror::ArtMethod* method, uint32_t dex_pc,
Ian Rogers62d6c772013-02-27 08:32:07 -0800186 const JValue& return_value) const
187 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Sebastien Hertz74109f62013-06-07 17:40:09 +0200188 if (UNLIKELY(HasMethodExitListeners())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800189 MethodExitEventImpl(thread, this_object, method, dex_pc, return_value);
190 }
191 }
192
193 // Inform listeners that a method has been exited due to an exception.
194 void MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700195 const mirror::ArtMethod* method, uint32_t dex_pc) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800196 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
197
198 // Inform listeners that the dex pc has moved (only supported by the interpreter).
199 void DexPcMovedEvent(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700200 const mirror::ArtMethod* method, uint32_t dex_pc) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800201 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Sebastien Hertz74109f62013-06-07 17:40:09 +0200202 if (UNLIKELY(HasDexPcListeners())) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800203 DexPcMovedEventImpl(thread, this_object, method, dex_pc);
204 }
205 }
206
207 // Inform listeners that an exception was caught.
208 void ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
Brian Carlstromea46f952013-07-30 01:26:50 -0700209 mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200210 mirror::Throwable* exception_object) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800211 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
212
213 // Called when an instrumented method is entered. The intended link register (lr) is saved so
214 // that returning causes a branch to the method exit stub. Generates method enter events.
215 void PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700216 mirror::ArtMethod* method, uintptr_t lr,
Jeff Hao9a916d32013-06-27 18:45:37 -0700217 bool interpreter_entry)
Ian Rogers62d6c772013-02-27 08:32:07 -0800218 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
219
220 // Called when an instrumented method is exited. Removes the pushed instrumentation frame
221 // returning the intended link register. Generates method exit events.
222 uint64_t PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc, uint64_t gpr_result,
223 uint64_t fpr_result)
224 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
225
226 // Pops an instrumentation frame from the current thread and generate an unwind event.
227 void PopMethodForUnwind(Thread* self, bool is_deoptimization) const
228 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
229
230 // Call back for configure stubs.
231 bool InstallStubsForClass(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
jeffhao725a9572012-11-13 18:20:12 -0800232
233 private:
Ian Rogers62d6c772013-02-27 08:32:07 -0800234 // Does the job of installing or removing instrumentation code within methods.
235 void ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter)
236 EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
237 LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::classlinker_classes_lock_);
jeffhao725a9572012-11-13 18:20:12 -0800238
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200239 void UpdateInterpreterHandlerTable() {
240 interpreter_handler_table_ = IsActive() ? kAlternativeHandlerTable : kMainHandlerTable;
241 }
242
Ian Rogers62d6c772013-02-27 08:32:07 -0800243 void MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700244 const mirror::ArtMethod* method, uint32_t dex_pc) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800245 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
246 void MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700247 const mirror::ArtMethod* method,
Ian Rogers62d6c772013-02-27 08:32:07 -0800248 uint32_t dex_pc, const JValue& return_value) const
249 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
250 void DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
Brian Carlstromea46f952013-07-30 01:26:50 -0700251 const mirror::ArtMethod* method, uint32_t dex_pc) const
Ian Rogers62d6c772013-02-27 08:32:07 -0800252 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
jeffhao725a9572012-11-13 18:20:12 -0800253
Brian Carlstromea46f952013-07-30 01:26:50 -0700254 // Have we hijacked ArtMethod::code_ so that it calls instrumentation/interpreter code?
Ian Rogers62d6c772013-02-27 08:32:07 -0800255 bool instrumentation_stubs_installed_;
256
Brian Carlstromea46f952013-07-30 01:26:50 -0700257 // Have we hijacked ArtMethod::code_ to reference the enter/exit stubs?
Ian Rogers62d6c772013-02-27 08:32:07 -0800258 bool entry_exit_stubs_installed_;
259
Brian Carlstromea46f952013-07-30 01:26:50 -0700260 // Have we hijacked ArtMethod::code_ to reference the enter interpreter stub?
Ian Rogers62d6c772013-02-27 08:32:07 -0800261 bool interpreter_stubs_installed_;
262
263 // Do we need the fidelity of events that we only get from running within the interpreter?
264 bool interpret_only_;
265
266 // Did the runtime request we only run in the interpreter? ie -Xint mode.
267 bool forced_interpret_only_;
268
269 // Do we have any listeners for method entry events? Short-cut to avoid taking the
270 // instrumentation_lock_.
271 bool have_method_entry_listeners_;
272
273 // Do we have any listeners for method exit events? Short-cut to avoid taking the
274 // instrumentation_lock_.
275 bool have_method_exit_listeners_;
276
277 // Do we have any listeners for method unwind events? Short-cut to avoid taking the
278 // instrumentation_lock_.
279 bool have_method_unwind_listeners_;
280
281 // Do we have any listeners for dex move events? Short-cut to avoid taking the
282 // instrumentation_lock_.
283 bool have_dex_pc_listeners_;
284
285 // Do we have any exception caught listeners? Short-cut to avoid taking the instrumentation_lock_.
286 bool have_exception_caught_listeners_;
287
288 // The event listeners, written to with the mutator_lock_ exclusively held.
289 std::list<InstrumentationListener*> method_entry_listeners_ GUARDED_BY(Locks::mutator_lock_);
290 std::list<InstrumentationListener*> method_exit_listeners_ GUARDED_BY(Locks::mutator_lock_);
291 std::list<InstrumentationListener*> method_unwind_listeners_ GUARDED_BY(Locks::mutator_lock_);
292 std::list<InstrumentationListener*> dex_pc_listeners_ GUARDED_BY(Locks::mutator_lock_);
293 std::list<InstrumentationListener*> exception_caught_listeners_ GUARDED_BY(Locks::mutator_lock_);
jeffhao725a9572012-11-13 18:20:12 -0800294
Ian Rogersfa824272013-11-05 16:12:57 -0800295 // Current interpreter handler table. This is updated each time the thread state flags are
296 // modified.
Sebastien Hertzee1997a2013-09-19 14:47:09 +0200297 InterpreterHandlerTable interpreter_handler_table_;
298
Ian Rogersfa824272013-11-05 16:12:57 -0800299 // Greater than 0 if quick alloc entry points instrumented.
300 // TODO: The access and changes to this is racy and should be guarded by a lock.
301 size_t quick_alloc_entry_points_instrumentation_counter_;
302
jeffhao725a9572012-11-13 18:20:12 -0800303 DISALLOW_COPY_AND_ASSIGN(Instrumentation);
304};
305
Ian Rogers62d6c772013-02-27 08:32:07 -0800306// An element in the instrumentation side stack maintained in art::Thread.
307struct InstrumentationStackFrame {
Brian Carlstromea46f952013-07-30 01:26:50 -0700308 InstrumentationStackFrame(mirror::Object* this_object, mirror::ArtMethod* method,
Jeff Hao9a916d32013-06-27 18:45:37 -0700309 uintptr_t return_pc, size_t frame_id, bool interpreter_entry)
310 : this_object_(this_object), method_(method), return_pc_(return_pc), frame_id_(frame_id),
311 interpreter_entry_(interpreter_entry) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800312 }
313
314 std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
315
316 mirror::Object* this_object_;
Brian Carlstromea46f952013-07-30 01:26:50 -0700317 mirror::ArtMethod* method_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800318 const uintptr_t return_pc_;
319 const size_t frame_id_;
Jeff Hao65d15d92013-07-16 16:39:33 -0700320 const bool interpreter_entry_;
Ian Rogers62d6c772013-02-27 08:32:07 -0800321};
322
323} // namespace instrumentation
jeffhao725a9572012-11-13 18:20:12 -0800324} // namespace art
325
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700326#endif // ART_RUNTIME_INSTRUMENTATION_H_