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 
GetArtJvmtiEvent(ArtJvmTiEnv * env,jvmtiEvent e)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:
ScopedEventDispatchEnvironment()55   ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
56     DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
57   }
58 
ScopedEventDispatchEnvironment(JNIEnv * env)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 
~ScopedEventDispatchEnvironment()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>
CollectEvents(art::Thread * thread,Args...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>
DispatchClassFileLoadHookEvent(art::Thread * thread,JNIEnv * jnienv,jclass class_being_redefined,jobject loader,const char * name,jobject protection_domain,jint class_data_len,const unsigned char * class_data,jint * new_class_data_len,unsigned char ** new_class_data)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>
DispatchEvent(art::Thread * thread,Args...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>
DispatchEvent(art::Thread * thread,JNIEnv * jnienv,Args...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>
DispatchEventOnEnv(ArtJvmTiEnv * env,art::Thread * thread,JNIEnv * jnienv,Args...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>
DispatchEventOnEnv(ArtJvmTiEnv * env,art::Thread * thread,Args...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>
ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,Args...args)319 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
320   handler.ExecuteCallback(args...);
321 }
322 
323 template <ArtJvmtiEvent kEvent, typename ...Args>
ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,JNIEnv * jnienv,Args...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>
ShouldDispatchOnThread(ArtJvmTiEnv * env,art::Thread * thread)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>
ShouldDispatch(ArtJvmTiEnv * env,art::Thread * thread,Args...args ATTRIBUTE_UNUSED)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 
RecalculateGlobalEventMask(ArtJvmtiEvent event)529 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
530   art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
531   RecalculateGlobalEventMaskLocked(event);
532 }
533 
RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event)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 
NeedsEventUpdate(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)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 
HandleChangedCapabilities(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)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