• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #ifndef ART_RUNTIME_INSTRUMENTATION_H_
18 #define ART_RUNTIME_INSTRUMENTATION_H_
19 
20 #include "base/macros.h"
21 #include "locks.h"
22 
23 #include <stdint.h>
24 #include <list>
25 
26 namespace art {
27 namespace mirror {
28   class ArtMethod;
29   class Class;
30   class Object;
31   class Throwable;
32 }  // namespace mirror
33 union JValue;
34 class Thread;
35 class ThrowLocation;
36 
37 namespace instrumentation {
38 
39 const bool kVerboseInstrumentation = false;
40 
41 // Instrumentation event listener API. Registered listeners will get the appropriate call back for
42 // the events they are listening for. The call backs supply the thread, method and dex_pc the event
43 // occurred upon. The thread may or may not be Thread::Current().
44 struct InstrumentationListener {
InstrumentationListenerInstrumentationListener45   InstrumentationListener() {}
~InstrumentationListenerInstrumentationListener46   virtual ~InstrumentationListener() {}
47 
48   // Call-back for when a method is entered.
49   virtual void MethodEntered(Thread* thread, mirror::Object* this_object,
50                              const mirror::ArtMethod* method,
51                              uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
52 
53   // Call-back for when a method is exited.
54   // TODO: its likely passing the return value would be useful, however, we may need to get and
55   //       parse the shorty to determine what kind of register holds the result.
56   virtual void MethodExited(Thread* thread, mirror::Object* this_object,
57                             const mirror::ArtMethod* method, uint32_t dex_pc,
58                             const JValue& return_value)
59       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
60 
61   // Call-back for when a method is popped due to an exception throw. A method will either cause a
62   // MethodExited call-back or a MethodUnwind call-back when its activation is removed.
63   virtual void MethodUnwind(Thread* thread, const mirror::ArtMethod* method,
64                             uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
65 
66   // Call-back for when the dex pc moves in a method.
67   virtual void DexPcMoved(Thread* thread, mirror::Object* this_object,
68                           const mirror::ArtMethod* method, uint32_t new_dex_pc)
69       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
70 
71   // Call-back when an exception is caught.
72   virtual void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location,
73                                mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
74                                mirror::Throwable* exception_object)
75       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
76 };
77 
78 // Instrumentation is a catch-all for when extra information is required from the runtime. The
79 // typical use for instrumentation is for profiling and debugging. Instrumentation may add stubs
80 // to method entry and exit, it may also force execution to be switched to the interpreter and
81 // trigger deoptimization.
82 class Instrumentation {
83  public:
84   enum InstrumentationEvent {
85     kMethodEntered = 1,
86     kMethodExited = 2,
87     kMethodUnwind = 4,
88     kDexPcMoved = 8,
89     kExceptionCaught = 16
90   };
91 
Instrumentation()92   Instrumentation() :
93       instrumentation_stubs_installed_(false), entry_exit_stubs_installed_(false),
94       interpreter_stubs_installed_(false),
95       interpret_only_(false), forced_interpret_only_(false),
96       have_method_entry_listeners_(false), have_method_exit_listeners_(false),
97       have_method_unwind_listeners_(false), have_dex_pc_listeners_(false),
98       have_exception_caught_listeners_(false) {}
99 
100   // Add a listener to be notified of the masked together sent of instrumentation events. This
101   // suspend the runtime to install stubs. You are expected to hold the mutator lock as a proxy
102   // for saying you should have suspended all threads (installing stubs while threads are running
103   // will break).
104   void AddListener(InstrumentationListener* listener, uint32_t events)
105       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
106       LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::classlinker_classes_lock_);
107 
108   // Removes a listener possibly removing instrumentation stubs.
109   void RemoveListener(InstrumentationListener* listener, uint32_t events)
110       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
111       LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::classlinker_classes_lock_);
112 
113   // Update the code of a method respecting any installed stubs.
114   void UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const;
115 
116   // Get the quick code for the given method. More efficient than asking the class linker as it
117   // will short-cut to GetCode if instrumentation and static method resolution stubs aren't
118   // installed.
119   const void* GetQuickCodeFor(const mirror::ArtMethod* method) const
120       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
121 
ForceInterpretOnly()122   void ForceInterpretOnly() {
123     interpret_only_ = true;
124     forced_interpret_only_ = true;
125   }
126 
127   // Called by ArtMethod::Invoke to determine dispatch mechanism.
InterpretOnly()128   bool InterpretOnly() const {
129     return interpret_only_;
130   }
131 
ShouldPortableCodeDeoptimize()132   bool ShouldPortableCodeDeoptimize() const {
133     return instrumentation_stubs_installed_;
134   }
135 
AreExitStubsInstalled()136   bool AreExitStubsInstalled() const {
137     return instrumentation_stubs_installed_;
138   }
139 
HasMethodEntryListeners()140   bool HasMethodEntryListeners() const {
141     return have_method_entry_listeners_;
142   }
143 
HasMethodExitListeners()144   bool HasMethodExitListeners() const {
145     return have_method_exit_listeners_;
146   }
147 
HasDexPcListeners()148   bool HasDexPcListeners() const {
149     return have_dex_pc_listeners_;
150   }
151 
152   // Inform listeners that a method has been entered. A dex PC is provided as we may install
153   // listeners into executing code and get method enter events for methods already on the stack.
MethodEnterEvent(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc)154   void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
155                         const mirror::ArtMethod* method, uint32_t dex_pc) const
156       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
157     if (UNLIKELY(HasMethodEntryListeners())) {
158       MethodEnterEventImpl(thread, this_object, method, dex_pc);
159     }
160   }
161 
162   // Inform listeners that a method has been exited.
MethodExitEvent(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc,const JValue & return_value)163   void MethodExitEvent(Thread* thread, mirror::Object* this_object,
164                        const mirror::ArtMethod* method, uint32_t dex_pc,
165                        const JValue& return_value) const
166       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
167     if (UNLIKELY(HasMethodExitListeners())) {
168       MethodExitEventImpl(thread, this_object, method, dex_pc, return_value);
169     }
170   }
171 
172   // Inform listeners that a method has been exited due to an exception.
173   void MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
174                          const mirror::ArtMethod* method, uint32_t dex_pc) const
175       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
176 
177   // Inform listeners that the dex pc has moved (only supported by the interpreter).
DexPcMovedEvent(Thread * thread,mirror::Object * this_object,const mirror::ArtMethod * method,uint32_t dex_pc)178   void DexPcMovedEvent(Thread* thread, mirror::Object* this_object,
179                        const mirror::ArtMethod* method, uint32_t dex_pc) const
180       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
181     if (UNLIKELY(HasDexPcListeners())) {
182       DexPcMovedEventImpl(thread, this_object, method, dex_pc);
183     }
184   }
185 
186   // Inform listeners that an exception was caught.
187   void ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
188                             mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
189                             mirror::Throwable* exception_object)
190       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
191 
192   // Called when an instrumented method is entered. The intended link register (lr) is saved so
193   // that returning causes a branch to the method exit stub. Generates method enter events.
194   void PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object,
195                                      mirror::ArtMethod* method, uintptr_t lr,
196                                      bool interpreter_entry)
197       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
198 
199   // Called when an instrumented method is exited. Removes the pushed instrumentation frame
200   // returning the intended link register. Generates method exit events.
201   uint64_t PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc, uint64_t gpr_result,
202                                         uint64_t fpr_result)
203       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
204 
205   // Pops an instrumentation frame from the current thread and generate an unwind event.
206   void PopMethodForUnwind(Thread* self, bool is_deoptimization) const
207       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
208 
209   // Call back for configure stubs.
210   bool InstallStubsForClass(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
211 
212  private:
213   // Does the job of installing or removing instrumentation code within methods.
214   void ConfigureStubs(bool require_entry_exit_stubs, bool require_interpreter)
215       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
216       LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::classlinker_classes_lock_);
217 
218   void MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
219                             const mirror::ArtMethod* method, uint32_t dex_pc) const
220       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
221   void MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
222                            const mirror::ArtMethod* method,
223                            uint32_t dex_pc, const JValue& return_value) const
224       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
225   void DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
226                            const mirror::ArtMethod* method, uint32_t dex_pc) const
227       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
228 
229   // Have we hijacked ArtMethod::code_ so that it calls instrumentation/interpreter code?
230   bool instrumentation_stubs_installed_;
231 
232   // Have we hijacked ArtMethod::code_ to reference the enter/exit stubs?
233   bool entry_exit_stubs_installed_;
234 
235   // Have we hijacked ArtMethod::code_ to reference the enter interpreter stub?
236   bool interpreter_stubs_installed_;
237 
238   // Do we need the fidelity of events that we only get from running within the interpreter?
239   bool interpret_only_;
240 
241   // Did the runtime request we only run in the interpreter? ie -Xint mode.
242   bool forced_interpret_only_;
243 
244   // Do we have any listeners for method entry events? Short-cut to avoid taking the
245   // instrumentation_lock_.
246   bool have_method_entry_listeners_;
247 
248   // Do we have any listeners for method exit events? Short-cut to avoid taking the
249   // instrumentation_lock_.
250   bool have_method_exit_listeners_;
251 
252   // Do we have any listeners for method unwind events? Short-cut to avoid taking the
253   // instrumentation_lock_.
254   bool have_method_unwind_listeners_;
255 
256   // Do we have any listeners for dex move events? Short-cut to avoid taking the
257   // instrumentation_lock_.
258   bool have_dex_pc_listeners_;
259 
260   // Do we have any exception caught listeners? Short-cut to avoid taking the instrumentation_lock_.
261   bool have_exception_caught_listeners_;
262 
263   // The event listeners, written to with the mutator_lock_ exclusively held.
264   std::list<InstrumentationListener*> method_entry_listeners_ GUARDED_BY(Locks::mutator_lock_);
265   std::list<InstrumentationListener*> method_exit_listeners_ GUARDED_BY(Locks::mutator_lock_);
266   std::list<InstrumentationListener*> method_unwind_listeners_ GUARDED_BY(Locks::mutator_lock_);
267   std::list<InstrumentationListener*> dex_pc_listeners_ GUARDED_BY(Locks::mutator_lock_);
268   std::list<InstrumentationListener*> exception_caught_listeners_ GUARDED_BY(Locks::mutator_lock_);
269 
270   DISALLOW_COPY_AND_ASSIGN(Instrumentation);
271 };
272 
273 // An element in the instrumentation side stack maintained in art::Thread.
274 struct InstrumentationStackFrame {
InstrumentationStackFrameInstrumentationStackFrame275   InstrumentationStackFrame(mirror::Object* this_object, mirror::ArtMethod* method,
276                             uintptr_t return_pc, size_t frame_id, bool interpreter_entry)
277       : this_object_(this_object), method_(method), return_pc_(return_pc), frame_id_(frame_id),
278         interpreter_entry_(interpreter_entry) {
279   }
280 
281   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
282 
283   mirror::Object* this_object_;
284   mirror::ArtMethod* method_;
285   const uintptr_t return_pc_;
286   const size_t frame_id_;
287   const bool interpreter_entry_;
288 };
289 
290 }  // namespace instrumentation
291 }  // namespace art
292 
293 #endif  // ART_RUNTIME_INSTRUMENTATION_H_
294