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