• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetArtJvmtiEvent(ArtJvmTiEnv * env,jvmtiEvent e)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:
ScopedEventDispatchEnvironment()58   ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
59     DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
60   }
61 
ScopedEventDispatchEnvironment(JNIEnv * env)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 
~ScopedEventDispatchEnvironment()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>
CollectEvents(art::Thread * thread,Args...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>
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)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>
DispatchEvent(art::Thread * thread,Args...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>
DispatchEvent(art::Thread * thread,JNIEnv * jnienv,Args...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>
DispatchEventOnEnv(ArtJvmTiEnv * env,art::Thread * thread,JNIEnv * jnienv,Args...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>
DispatchEventOnEnv(ArtJvmTiEnv * env,art::Thread * thread,Args...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>
ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,Args...args)322 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
323   handler.ExecuteCallback(args...);
324 }
325 
326 template <ArtJvmtiEvent kEvent, typename ...Args>
ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,JNIEnv * jnienv,Args...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:
ScopedDisablePopFrameScopedDisablePopFrame427   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 
~ScopedDisablePopFrameScopedDisablePopFrame440   ~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>
DispatchClassLoadOrPrepareEvent(art::Thread * thread,JNIEnv * jnienv,jthread jni_thread,jclass klass)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>
ShouldDispatchOnThread(ArtJvmTiEnv * env,art::Thread * thread)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>
ShouldDispatch(ArtJvmTiEnv * env,art::Thread * thread,Args...args ATTRIBUTE_UNUSED)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 
RecalculateGlobalEventMask(ArtJvmtiEvent event)594 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
595   art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
596   RecalculateGlobalEventMaskLocked(event);
597 }
598 
RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event)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 
NeedsEventUpdate(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)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 
HandleChangedCapabilities(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)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