Home | History | Annotate | Download | only in openjdkjvmti
      1 /*
      2  * Copyright (C) 2016 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_OPENJDKJVMTI_EVENTS_INL_H_
     18 #define ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
     19 
     20 #include <array>
     21 
     22 #include "events.h"
     23 
     24 #include "art_jvmti.h"
     25 
     26 namespace openjdkjvmti {
     27 
     28 static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
     29   if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
     30     if (env->capabilities.can_retransform_classes) {
     31       return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
     32     } else {
     33       return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
     34     }
     35   } else {
     36     return static_cast<ArtJvmtiEvent>(e);
     37   }
     38 }
     39 
     40 namespace impl {
     41 
     42 // Infrastructure to achieve type safety for event dispatch.
     43 
     44 #define FORALL_EVENT_TYPES(fn)                                                       \
     45   fn(VMInit,                  ArtJvmtiEvent::kVmInit)                                \
     46   fn(VMDeath,                 ArtJvmtiEvent::kVmDeath)                               \
     47   fn(ThreadStart,             ArtJvmtiEvent::kThreadStart)                           \
     48   fn(ThreadEnd,               ArtJvmtiEvent::kThreadEnd)                             \
     49   fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookRetransformable)      \
     50   fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookNonRetransformable)   \
     51   fn(ClassLoad,               ArtJvmtiEvent::kClassLoad)                             \
     52   fn(ClassPrepare,            ArtJvmtiEvent::kClassPrepare)                          \
     53   fn(VMStart,                 ArtJvmtiEvent::kVmStart)                               \
     54   fn(Exception,               ArtJvmtiEvent::kException)                             \
     55   fn(ExceptionCatch,          ArtJvmtiEvent::kExceptionCatch)                        \
     56   fn(SingleStep,              ArtJvmtiEvent::kSingleStep)                            \
     57   fn(FramePop,                ArtJvmtiEvent::kFramePop)                              \
     58   fn(Breakpoint,              ArtJvmtiEvent::kBreakpoint)                            \
     59   fn(FieldAccess,             ArtJvmtiEvent::kFieldAccess)                           \
     60   fn(FieldModification,       ArtJvmtiEvent::kFieldModification)                     \
     61   fn(MethodEntry,             ArtJvmtiEvent::kMethodEntry)                           \
     62   fn(MethodExit,              ArtJvmtiEvent::kMethodExit)                            \
     63   fn(NativeMethodBind,        ArtJvmtiEvent::kNativeMethodBind)                      \
     64   fn(CompiledMethodLoad,      ArtJvmtiEvent::kCompiledMethodLoad)                    \
     65   fn(CompiledMethodUnload,    ArtJvmtiEvent::kCompiledMethodUnload)                  \
     66   fn(DynamicCodeGenerated,    ArtJvmtiEvent::kDynamicCodeGenerated)                  \
     67   fn(DataDumpRequest,         ArtJvmtiEvent::kDataDumpRequest)                       \
     68   fn(MonitorWait,             ArtJvmtiEvent::kMonitorWait)                           \
     69   fn(MonitorWaited,           ArtJvmtiEvent::kMonitorWaited)                         \
     70   fn(MonitorContendedEnter,   ArtJvmtiEvent::kMonitorContendedEnter)                 \
     71   fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered)               \
     72   fn(ResourceExhausted,       ArtJvmtiEvent::kResourceExhausted)                     \
     73   fn(GarbageCollectionStart,  ArtJvmtiEvent::kGarbageCollectionStart)                \
     74   fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish)               \
     75   fn(ObjectFree,              ArtJvmtiEvent::kObjectFree)                            \
     76   fn(VMObjectAlloc,           ArtJvmtiEvent::kVmObjectAlloc)
     77 
     78 template <ArtJvmtiEvent kEvent>
     79 struct EventFnType {
     80 };
     81 
     82 #define EVENT_FN_TYPE(name, enum_name)               \
     83 template <>                                          \
     84 struct EventFnType<enum_name> {                      \
     85   using type = decltype(jvmtiEventCallbacks().name); \
     86 };
     87 
     88 FORALL_EVENT_TYPES(EVENT_FN_TYPE)
     89 
     90 #undef EVENT_FN_TYPE
     91 
     92 template <ArtJvmtiEvent kEvent>
     93 ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
     94 
     95 #define GET_CALLBACK(name, enum_name)                                     \
     96 template <>                                                               \
     97 ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
     98     ArtJvmTiEnv* env) {                                                   \
     99   if (env->event_callbacks == nullptr) {                                  \
    100     return nullptr;                                                       \
    101   }                                                                       \
    102   return env->event_callbacks->name;                                      \
    103 }
    104 
    105 FORALL_EVENT_TYPES(GET_CALLBACK)
    106 
    107 #undef GET_CALLBACK
    108 
    109 #undef FORALL_EVENT_TYPES
    110 
    111 }  // namespace impl
    112 
    113 // C++ does not allow partial template function specialization. The dispatch for our separated
    114 // ClassFileLoadHook event types is the same, so use this helper for code deduplication.
    115 // TODO Locking of some type!
    116 template <ArtJvmtiEvent kEvent>
    117 inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
    118                                                          JNIEnv* jnienv,
    119                                                          jclass class_being_redefined,
    120                                                          jobject loader,
    121                                                          const char* name,
    122                                                          jobject protection_domain,
    123                                                          jint class_data_len,
    124                                                          const unsigned char* class_data,
    125                                                          jint* new_class_data_len,
    126                                                          unsigned char** new_class_data) const {
    127   static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
    128                 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
    129   DCHECK(*new_class_data == nullptr);
    130   jint current_len = class_data_len;
    131   unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
    132   ArtJvmTiEnv* last_env = nullptr;
    133   for (ArtJvmTiEnv* env : envs) {
    134     if (env == nullptr) {
    135       continue;
    136     }
    137     if (ShouldDispatch<kEvent>(env, thread)) {
    138       jint new_len = 0;
    139       unsigned char* new_data = nullptr;
    140       auto callback = impl::GetCallback<kEvent>(env);
    141       callback(env,
    142                jnienv,
    143                class_being_redefined,
    144                loader,
    145                name,
    146                protection_domain,
    147                current_len,
    148                current_class_data,
    149                &new_len,
    150                &new_data);
    151       if (new_data != nullptr && new_data != current_class_data) {
    152         // Destroy the data the last transformer made. We skip this if the previous state was the
    153         // initial one since we don't know here which jvmtiEnv allocated it.
    154         // NB Currently this doesn't matter since all allocations just go to malloc but in the
    155         // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
    156         if (last_env != nullptr) {
    157           last_env->Deallocate(current_class_data);
    158         }
    159         last_env = env;
    160         current_class_data = new_data;
    161         current_len = new_len;
    162       }
    163     }
    164   }
    165   if (last_env != nullptr) {
    166     *new_class_data_len = current_len;
    167     *new_class_data = current_class_data;
    168   }
    169 }
    170 
    171 // Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
    172 // exactly the argument types of the corresponding Jvmti kEvent function pointer.
    173 
    174 template <ArtJvmtiEvent kEvent, typename ...Args>
    175 inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
    176   for (ArtJvmTiEnv* env : envs) {
    177     if (env != nullptr) {
    178       DispatchEvent<kEvent, Args...>(env, thread, args...);
    179     }
    180   }
    181 }
    182 
    183 template <ArtJvmtiEvent kEvent, typename ...Args>
    184 inline void EventHandler::DispatchEvent(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
    185   using FnType = void(jvmtiEnv*, Args...);
    186   if (ShouldDispatch<kEvent>(env, thread)) {
    187     FnType* callback = impl::GetCallback<kEvent>(env);
    188     if (callback != nullptr) {
    189       (*callback)(env, args...);
    190     }
    191   }
    192 }
    193 
    194 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out
    195 // variable.
    196 template <>
    197 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
    198                                                                           JNIEnv* jnienv,
    199                                                                           jthread jni_thread,
    200                                                                           jmethodID method,
    201                                                                           void* cur_method,
    202                                                                           void** new_method) const {
    203   *new_method = cur_method;
    204   for (ArtJvmTiEnv* env : envs) {
    205     if (env != nullptr && ShouldDispatch<ArtJvmtiEvent::kNativeMethodBind>(env, thread)) {
    206       auto callback = impl::GetCallback<ArtJvmtiEvent::kNativeMethodBind>(env);
    207       (*callback)(env, jnienv, jni_thread, method, cur_method, new_method);
    208       if (*new_method != nullptr) {
    209         cur_method = *new_method;
    210       }
    211     }
    212   }
    213 }
    214 
    215 // C++ does not allow partial template function specialization. The dispatch for our separated
    216 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
    217 // The following two DispatchEvent specializations dispatch to it.
    218 template <>
    219 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    220     art::Thread* thread,
    221     JNIEnv* jnienv,
    222     jclass class_being_redefined,
    223     jobject loader,
    224     const char* name,
    225     jobject protection_domain,
    226     jint class_data_len,
    227     const unsigned char* class_data,
    228     jint* new_class_data_len,
    229     unsigned char** new_class_data) const {
    230   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    231       thread,
    232       jnienv,
    233       class_being_redefined,
    234       loader,
    235       name,
    236       protection_domain,
    237       class_data_len,
    238       class_data,
    239       new_class_data_len,
    240       new_class_data);
    241 }
    242 template <>
    243 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    244     art::Thread* thread,
    245     JNIEnv* jnienv,
    246     jclass class_being_redefined,
    247     jobject loader,
    248     const char* name,
    249     jobject protection_domain,
    250     jint class_data_len,
    251     const unsigned char* class_data,
    252     jint* new_class_data_len,
    253     unsigned char** new_class_data) const {
    254   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    255       thread,
    256       jnienv,
    257       class_being_redefined,
    258       loader,
    259       name,
    260       protection_domain,
    261       class_data_len,
    262       class_data,
    263       new_class_data_len,
    264       new_class_data);
    265 }
    266 
    267 template <ArtJvmtiEvent kEvent>
    268 inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
    269                                          art::Thread* thread) {
    270   bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
    271 
    272   if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
    273     EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
    274     dispatch = mask != nullptr && mask->Test(kEvent);
    275   }
    276   return dispatch;
    277 }
    278 
    279 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
    280   bool union_value = false;
    281   for (const ArtJvmTiEnv* stored_env : envs) {
    282     if (stored_env == nullptr) {
    283       continue;
    284     }
    285     union_value |= stored_env->event_masks.global_event_mask.Test(event);
    286     union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
    287     if (union_value) {
    288       break;
    289     }
    290   }
    291   global_mask.Set(event, union_value);
    292 }
    293 
    294 inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
    295                                            const jvmtiCapabilities& caps,
    296                                            bool added) {
    297   ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
    298                               : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
    299   return caps.can_retransform_classes == 1 &&
    300       IsEventEnabledAnywhere(event) &&
    301       env->event_masks.IsEnabledAnywhere(event);
    302 }
    303 
    304 inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
    305                                                     const jvmtiCapabilities& caps,
    306                                                     bool added) {
    307   if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
    308     env->event_masks.HandleChangedCapabilities(caps, added);
    309     if (caps.can_retransform_classes == 1) {
    310       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
    311       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
    312     }
    313   }
    314 }
    315 
    316 }  // namespace openjdkjvmti
    317 
    318 #endif  // ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
    319