Home | History | Annotate | Download | only in runtime
      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 {
     45   InstrumentationListener() {}
     46   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 
     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 
    122   void ForceInterpretOnly() {
    123     interpret_only_ = true;
    124     forced_interpret_only_ = true;
    125   }
    126 
    127   // Called by ArtMethod::Invoke to determine dispatch mechanism.
    128   bool InterpretOnly() const {
    129     return interpret_only_;
    130   }
    131 
    132   bool ShouldPortableCodeDeoptimize() const {
    133     return instrumentation_stubs_installed_;
    134   }
    135 
    136   bool AreExitStubsInstalled() const {
    137     return instrumentation_stubs_installed_;
    138   }
    139 
    140   bool HasMethodEntryListeners() const {
    141     return have_method_entry_listeners_;
    142   }
    143 
    144   bool HasMethodExitListeners() const {
    145     return have_method_exit_listeners_;
    146   }
    147 
    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.
    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.
    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).
    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 {
    275   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