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_OPENJDKJVMTI_EVENTS_INL_H_
     18 #define ART_OPENJDKJVMTI_EVENTS_INL_H_
     19 
     20 #include <array>
     21 #include <type_traits>
     22 #include <tuple>
     23 
     24 #include "base/mutex-inl.h"
     25 #include "events.h"
     26 #include "jni_internal.h"
     27 #include "nativehelper/scoped_local_ref.h"
     28 #include "scoped_thread_state_change-inl.h"
     29 #include "ti_breakpoint.h"
     30 
     31 #include "art_jvmti.h"
     32 
     33 namespace openjdkjvmti {
     34 
     35 static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
     36   if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
     37     if (env->capabilities.can_retransform_classes) {
     38       return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
     39     } else {
     40       return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
     41     }
     42   } else {
     43     return static_cast<ArtJvmtiEvent>(e);
     44   }
     45 }
     46 
     47 namespace impl {
     48 
     49 // Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash
     50 // pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI
     51 // specification we allow exceptions originating from events to overwrite the current exception,
     52 // including exceptions originating from earlier events.
     53 class ScopedEventDispatchEnvironment FINAL : public art::ValueObject {
     54  public:
     55   ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
     56     DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
     57   }
     58 
     59   explicit ScopedEventDispatchEnvironment(JNIEnv* env)
     60       : env_(env),
     61         throw_(env_, env_->ExceptionOccurred()) {
     62     DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
     63     // The spec doesn't say how much local data should be there, so we just give 128 which seems
     64     // likely to be enough for most cases.
     65     env_->PushLocalFrame(128);
     66     env_->ExceptionClear();
     67   }
     68 
     69   ~ScopedEventDispatchEnvironment() {
     70     if (env_ != nullptr) {
     71       if (throw_.get() != nullptr && !env_->ExceptionCheck()) {
     72         // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
     73         // of the newest exception.
     74         env_->Throw(throw_.get());
     75       }
     76       env_->PopLocalFrame(nullptr);
     77     }
     78     DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
     79   }
     80 
     81  private:
     82   JNIEnv* env_;
     83   ScopedLocalRef<jthrowable> throw_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
     86 };
     87 
     88 // Infrastructure to achieve type safety for event dispatch.
     89 
     90 #define FORALL_EVENT_TYPES(fn)                                                       \
     91   fn(VMInit,                  ArtJvmtiEvent::kVmInit)                                \
     92   fn(VMDeath,                 ArtJvmtiEvent::kVmDeath)                               \
     93   fn(ThreadStart,             ArtJvmtiEvent::kThreadStart)                           \
     94   fn(ThreadEnd,               ArtJvmtiEvent::kThreadEnd)                             \
     95   fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookRetransformable)      \
     96   fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookNonRetransformable)   \
     97   fn(ClassLoad,               ArtJvmtiEvent::kClassLoad)                             \
     98   fn(ClassPrepare,            ArtJvmtiEvent::kClassPrepare)                          \
     99   fn(VMStart,                 ArtJvmtiEvent::kVmStart)                               \
    100   fn(Exception,               ArtJvmtiEvent::kException)                             \
    101   fn(ExceptionCatch,          ArtJvmtiEvent::kExceptionCatch)                        \
    102   fn(SingleStep,              ArtJvmtiEvent::kSingleStep)                            \
    103   fn(FramePop,                ArtJvmtiEvent::kFramePop)                              \
    104   fn(Breakpoint,              ArtJvmtiEvent::kBreakpoint)                            \
    105   fn(FieldAccess,             ArtJvmtiEvent::kFieldAccess)                           \
    106   fn(FieldModification,       ArtJvmtiEvent::kFieldModification)                     \
    107   fn(MethodEntry,             ArtJvmtiEvent::kMethodEntry)                           \
    108   fn(MethodExit,              ArtJvmtiEvent::kMethodExit)                            \
    109   fn(NativeMethodBind,        ArtJvmtiEvent::kNativeMethodBind)                      \
    110   fn(CompiledMethodLoad,      ArtJvmtiEvent::kCompiledMethodLoad)                    \
    111   fn(CompiledMethodUnload,    ArtJvmtiEvent::kCompiledMethodUnload)                  \
    112   fn(DynamicCodeGenerated,    ArtJvmtiEvent::kDynamicCodeGenerated)                  \
    113   fn(DataDumpRequest,         ArtJvmtiEvent::kDataDumpRequest)                       \
    114   fn(MonitorWait,             ArtJvmtiEvent::kMonitorWait)                           \
    115   fn(MonitorWaited,           ArtJvmtiEvent::kMonitorWaited)                         \
    116   fn(MonitorContendedEnter,   ArtJvmtiEvent::kMonitorContendedEnter)                 \
    117   fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered)               \
    118   fn(ResourceExhausted,       ArtJvmtiEvent::kResourceExhausted)                     \
    119   fn(GarbageCollectionStart,  ArtJvmtiEvent::kGarbageCollectionStart)                \
    120   fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish)               \
    121   fn(ObjectFree,              ArtJvmtiEvent::kObjectFree)                            \
    122   fn(VMObjectAlloc,           ArtJvmtiEvent::kVmObjectAlloc)                         \
    123   fn(DdmPublishChunk,         ArtJvmtiEvent::kDdmPublishChunk)
    124 
    125 template <ArtJvmtiEvent kEvent>
    126 struct EventFnType {
    127 };
    128 
    129 #define EVENT_FN_TYPE(name, enum_name)                    \
    130 template <>                                               \
    131 struct EventFnType<enum_name> {                           \
    132   using type = decltype(ArtJvmtiEventCallbacks().name);   \
    133 };
    134 
    135 FORALL_EVENT_TYPES(EVENT_FN_TYPE)
    136 
    137 #undef EVENT_FN_TYPE
    138 
    139 #define MAKE_EVENT_HANDLER_FUNC(name, enum_name)                                          \
    140 template<>                                                                                \
    141 struct EventHandlerFunc<enum_name> {                                                      \
    142   using EventFnType = typename impl::EventFnType<enum_name>::type;                        \
    143   explicit EventHandlerFunc(ArtJvmTiEnv* env)                                             \
    144       : env_(env),                                                                        \
    145         fn_(env_->event_callbacks == nullptr ? nullptr : env_->event_callbacks->name) { } \
    146                                                                                           \
    147   template <typename ...Args>                                                             \
    148   ALWAYS_INLINE                                                                           \
    149   void ExecuteCallback(JNIEnv* jnienv, Args... args) const {                              \
    150     if (fn_ != nullptr) {                                                                 \
    151       ScopedEventDispatchEnvironment sede(jnienv);                                        \
    152       DoExecute(jnienv, args...);                                                         \
    153     }                                                                                     \
    154   }                                                                                       \
    155                                                                                           \
    156   template <typename ...Args>                                                             \
    157   ALWAYS_INLINE                                                                           \
    158   void ExecuteCallback(Args... args) const {                                              \
    159     if (fn_ != nullptr) {                                                                 \
    160       ScopedEventDispatchEnvironment sede;                                                \
    161       DoExecute(args...);                                                                 \
    162     }                                                                                     \
    163   }                                                                                       \
    164                                                                                           \
    165  private:                                                                                 \
    166   template <typename ...Args>                                                             \
    167   ALWAYS_INLINE                                                                           \
    168   inline void DoExecute(Args... args) const {                                             \
    169     static_assert(std::is_same<EventFnType, void(*)(jvmtiEnv*, Args...)>::value,          \
    170           "Unexpected different type of ExecuteCallback");                                \
    171     fn_(env_, args...);                                                                   \
    172   }                                                                                       \
    173                                                                                           \
    174  public:                                                                                  \
    175   ArtJvmTiEnv* env_;                                                                      \
    176   EventFnType fn_;                                                                        \
    177 };
    178 
    179 FORALL_EVENT_TYPES(MAKE_EVENT_HANDLER_FUNC)
    180 
    181 #undef MAKE_EVENT_HANDLER_FUNC
    182 
    183 #undef FORALL_EVENT_TYPES
    184 
    185 }  // namespace impl
    186 
    187 template <ArtJvmtiEvent kEvent, typename ...Args>
    188 inline std::vector<impl::EventHandlerFunc<kEvent>> EventHandler::CollectEvents(art::Thread* thread,
    189                                                                                Args... args) const {
    190   art::ReaderMutexLock mu(thread, envs_lock_);
    191   std::vector<impl::EventHandlerFunc<kEvent>> handlers;
    192   for (ArtJvmTiEnv* env : envs) {
    193     if (ShouldDispatch<kEvent>(env, thread, args...)) {
    194       impl::EventHandlerFunc<kEvent> h(env);
    195       handlers.push_back(h);
    196     }
    197   }
    198   return handlers;
    199 }
    200 
    201 // C++ does not allow partial template function specialization. The dispatch for our separated
    202 // ClassFileLoadHook event types is the same, so use this helper for code deduplication.
    203 template <ArtJvmtiEvent kEvent>
    204 inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
    205                                                          JNIEnv* jnienv,
    206                                                          jclass class_being_redefined,
    207                                                          jobject loader,
    208                                                          const char* name,
    209                                                          jobject protection_domain,
    210                                                          jint class_data_len,
    211                                                          const unsigned char* class_data,
    212                                                          jint* new_class_data_len,
    213                                                          unsigned char** new_class_data) const {
    214   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
    215   static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
    216                 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
    217   DCHECK(*new_class_data == nullptr);
    218   jint current_len = class_data_len;
    219   unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
    220   std::vector<impl::EventHandlerFunc<kEvent>> handlers =
    221       CollectEvents<kEvent>(thread,
    222                             jnienv,
    223                             class_being_redefined,
    224                             loader,
    225                             name,
    226                             protection_domain,
    227                             class_data_len,
    228                             class_data,
    229                             new_class_data_len,
    230                             new_class_data);
    231   ArtJvmTiEnv* last_env = nullptr;
    232   for (const impl::EventHandlerFunc<kEvent>& event : handlers) {
    233     jint new_len = 0;
    234     unsigned char* new_data = nullptr;
    235     ExecuteCallback<kEvent>(event,
    236                             jnienv,
    237                             class_being_redefined,
    238                             loader,
    239                             name,
    240                             protection_domain,
    241                             current_len,
    242                             static_cast<const unsigned char*>(current_class_data),
    243                             &new_len,
    244                             &new_data);
    245     if (new_data != nullptr && new_data != current_class_data) {
    246       // Destroy the data the last transformer made. We skip this if the previous state was the
    247       // initial one since we don't know here which jvmtiEnv allocated it.
    248       // NB Currently this doesn't matter since all allocations just go to malloc but in the
    249       // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
    250       if (last_env != nullptr) {
    251         last_env->Deallocate(current_class_data);
    252       }
    253       last_env = event.env_;
    254       current_class_data = new_data;
    255       current_len = new_len;
    256     }
    257   }
    258   if (last_env != nullptr) {
    259     *new_class_data_len = current_len;
    260     *new_class_data = current_class_data;
    261   }
    262 }
    263 
    264 // Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
    265 // exactly the argument types of the corresponding Jvmti kEvent function pointer.
    266 
    267 template <ArtJvmtiEvent kEvent, typename ...Args>
    268 inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
    269   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
    270   static_assert(!std::is_same<JNIEnv*,
    271                               typename std::decay_t<
    272                                   std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
    273                 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
    274   DCHECK(thread == nullptr || !thread->IsExceptionPending());
    275   std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, args...);
    276   for (auto event : events) {
    277     ExecuteCallback<kEvent>(event, args...);
    278   }
    279 }
    280 
    281 template <ArtJvmtiEvent kEvent, typename ...Args>
    282 inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
    283   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
    284   std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
    285                                                                              jnienv,
    286                                                                              args...);
    287   for (auto event : events) {
    288     ExecuteCallback<kEvent>(event, jnienv, args...);
    289   }
    290 }
    291 
    292 template <ArtJvmtiEvent kEvent, typename ...Args>
    293 inline void EventHandler::DispatchEventOnEnv(
    294     ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
    295   DCHECK(env != nullptr);
    296   if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
    297     art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
    298     impl::EventHandlerFunc<kEvent> func(env);
    299     ExecuteCallback<kEvent>(func, jnienv, args...);
    300   }
    301 }
    302 
    303 template <ArtJvmtiEvent kEvent, typename ...Args>
    304 inline void EventHandler::DispatchEventOnEnv(
    305     ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
    306   static_assert(!std::is_same<JNIEnv*,
    307                               typename std::decay_t<
    308                                   std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
    309                 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
    310   DCHECK(env != nullptr);
    311   if (ShouldDispatch<kEvent, Args...>(env, thread, args...)) {
    312     art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
    313     impl::EventHandlerFunc<kEvent> func(env);
    314     ExecuteCallback<kEvent>(func, args...);
    315   }
    316 }
    317 
    318 template <ArtJvmtiEvent kEvent, typename ...Args>
    319 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
    320   handler.ExecuteCallback(args...);
    321 }
    322 
    323 template <ArtJvmtiEvent kEvent, typename ...Args>
    324 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
    325                                           JNIEnv* jnienv,
    326                                           Args... args) {
    327   handler.ExecuteCallback(jnienv, args...);
    328 }
    329 
    330 // Events that need custom logic for if we send the event but are otherwise normal. This includes
    331 // the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
    332 
    333 // Need to give custom specializations for Breakpoint since it needs to filter out which particular
    334 // methods/dex_pcs agents get notified on.
    335 template <>
    336 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
    337     ArtJvmTiEnv* env,
    338     art::Thread* thread,
    339     JNIEnv* jnienv ATTRIBUTE_UNUSED,
    340     jthread jni_thread ATTRIBUTE_UNUSED,
    341     jmethodID jmethod,
    342     jlocation location) const {
    343   art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
    344   art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
    345   return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
    346       env->breakpoints.find({method, location}) != env->breakpoints.end();
    347 }
    348 
    349 template <>
    350 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
    351     ArtJvmTiEnv* env,
    352     art::Thread* thread,
    353     JNIEnv* jnienv ATTRIBUTE_UNUSED,
    354     jthread jni_thread ATTRIBUTE_UNUSED,
    355     jmethodID jmethod ATTRIBUTE_UNUSED,
    356     jboolean is_exception ATTRIBUTE_UNUSED,
    357     const art::ShadowFrame* frame) const {
    358   // Search for the frame. Do this before checking if we need to send the event so that we don't
    359   // have to deal with use-after-free or the frames being reallocated later.
    360   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
    361   return env->notify_frames.erase(frame) != 0 &&
    362       ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
    363 }
    364 
    365 // Need to give custom specializations for FieldAccess and FieldModification since they need to
    366 // filter out which particular fields agents want to get notified on.
    367 // TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
    368 // could make the system more performant.
    369 template <>
    370 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
    371     ArtJvmTiEnv* env,
    372     art::Thread* thread,
    373     JNIEnv* jnienv ATTRIBUTE_UNUSED,
    374     jthread jni_thread ATTRIBUTE_UNUSED,
    375     jmethodID method ATTRIBUTE_UNUSED,
    376     jlocation location ATTRIBUTE_UNUSED,
    377     jclass field_klass ATTRIBUTE_UNUSED,
    378     jobject object ATTRIBUTE_UNUSED,
    379     jfieldID field,
    380     char type_char ATTRIBUTE_UNUSED,
    381     jvalue val ATTRIBUTE_UNUSED) const {
    382   art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
    383   return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
    384       env->modify_watched_fields.find(
    385           art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
    386 }
    387 
    388 template <>
    389 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
    390     ArtJvmTiEnv* env,
    391     art::Thread* thread,
    392     JNIEnv* jnienv ATTRIBUTE_UNUSED,
    393     jthread jni_thread ATTRIBUTE_UNUSED,
    394     jmethodID method ATTRIBUTE_UNUSED,
    395     jlocation location ATTRIBUTE_UNUSED,
    396     jclass field_klass ATTRIBUTE_UNUSED,
    397     jobject object ATTRIBUTE_UNUSED,
    398     jfieldID field) const {
    399   art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
    400   return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
    401       env->access_watched_fields.find(
    402           art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
    403 }
    404 
    405 // Need to give custom specializations for FramePop since it needs to filter out which particular
    406 // agents get the event. This specialization gets an extra argument so we can determine which (if
    407 // any) environments have the frame pop.
    408 // TODO It might be useful to use more template magic to have this only define ShouldDispatch or
    409 // something.
    410 template <>
    411 inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
    412     impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
    413     JNIEnv* jnienv,
    414     jthread jni_thread,
    415     jmethodID jmethod,
    416     jboolean is_exception,
    417     const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
    418   ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
    419 }
    420 
    421 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out
    422 // variable.
    423 template <>
    424 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
    425                                                                           JNIEnv* jnienv,
    426                                                                           jthread jni_thread,
    427                                                                           jmethodID method,
    428                                                                           void* cur_method,
    429                                                                           void** new_method) const {
    430   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
    431   std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
    432       CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
    433                                                       jnienv,
    434                                                       jni_thread,
    435                                                       method,
    436                                                       cur_method,
    437                                                       new_method);
    438   *new_method = cur_method;
    439   for (auto event : events) {
    440     *new_method = cur_method;
    441     ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
    442                                                       jnienv,
    443                                                       jni_thread,
    444                                                       method,
    445                                                       cur_method,
    446                                                       new_method);
    447     if (*new_method != nullptr) {
    448       cur_method = *new_method;
    449     }
    450   }
    451   *new_method = cur_method;
    452 }
    453 
    454 // C++ does not allow partial template function specialization. The dispatch for our separated
    455 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
    456 // The following two DispatchEvent specializations dispatch to it.
    457 template <>
    458 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    459     art::Thread* thread,
    460     JNIEnv* jnienv,
    461     jclass class_being_redefined,
    462     jobject loader,
    463     const char* name,
    464     jobject protection_domain,
    465     jint class_data_len,
    466     const unsigned char* class_data,
    467     jint* new_class_data_len,
    468     unsigned char** new_class_data) const {
    469   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    470       thread,
    471       jnienv,
    472       class_being_redefined,
    473       loader,
    474       name,
    475       protection_domain,
    476       class_data_len,
    477       class_data,
    478       new_class_data_len,
    479       new_class_data);
    480 }
    481 
    482 template <>
    483 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    484     art::Thread* thread,
    485     JNIEnv* jnienv,
    486     jclass class_being_redefined,
    487     jobject loader,
    488     const char* name,
    489     jobject protection_domain,
    490     jint class_data_len,
    491     const unsigned char* class_data,
    492     jint* new_class_data_len,
    493     unsigned char** new_class_data) const {
    494   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    495       thread,
    496       jnienv,
    497       class_being_redefined,
    498       loader,
    499       name,
    500       protection_domain,
    501       class_data_len,
    502       class_data,
    503       new_class_data_len,
    504       new_class_data);
    505 }
    506 
    507 template <ArtJvmtiEvent kEvent>
    508 inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const {
    509   bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
    510 
    511   if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
    512     EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
    513     dispatch = mask != nullptr && mask->Test(kEvent);
    514   }
    515   return dispatch;
    516 }
    517 
    518 template <ArtJvmtiEvent kEvent, typename ...Args>
    519 inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
    520                                          art::Thread* thread,
    521                                          Args... args ATTRIBUTE_UNUSED) const {
    522   static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
    523                              void(*)(jvmtiEnv*, Args...)>::value,
    524                 "Unexpected different type of shouldDispatch");
    525 
    526   return ShouldDispatchOnThread<kEvent>(env, thread);
    527 }
    528 
    529 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
    530   art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
    531   RecalculateGlobalEventMaskLocked(event);
    532 }
    533 
    534 inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) {
    535   bool union_value = false;
    536   for (const ArtJvmTiEnv* stored_env : envs) {
    537     if (stored_env == nullptr) {
    538       continue;
    539     }
    540     union_value |= stored_env->event_masks.global_event_mask.Test(event);
    541     union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
    542     if (union_value) {
    543       break;
    544     }
    545   }
    546   global_mask.Set(event, union_value);
    547 }
    548 
    549 inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
    550                                            const jvmtiCapabilities& caps,
    551                                            bool added) {
    552   ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
    553                               : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
    554   return (added && caps.can_access_local_variables == 1) ||
    555       caps.can_generate_breakpoint_events == 1 ||
    556       (caps.can_retransform_classes == 1 &&
    557        IsEventEnabledAnywhere(event) &&
    558        env->event_masks.IsEnabledAnywhere(event));
    559 }
    560 
    561 inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
    562                                                     const jvmtiCapabilities& caps,
    563                                                     bool added) {
    564   if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
    565     env->event_masks.HandleChangedCapabilities(caps, added);
    566     if (caps.can_retransform_classes == 1) {
    567       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
    568       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
    569     }
    570     if (added && caps.can_access_local_variables == 1) {
    571       HandleLocalAccessCapabilityAdded();
    572     }
    573     if (caps.can_generate_breakpoint_events == 1) {
    574       HandleBreakpointEventsChanged(added);
    575     }
    576   }
    577 }
    578 
    579 }  // namespace openjdkjvmti
    580 
    581 #endif  // ART_OPENJDKJVMTI_EVENTS_INL_H_
    582