• 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 suitably provisioned. Events with JNIEnvs
53 // need to stash pending exceptions since they can cause new ones to be thrown. In accordance with
54 // the JVMTI specification we allow exceptions originating from events to overwrite the current
55 // exception, 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   fn(ObsoleteObjectCreated,     ArtJvmtiEvent::kObsoleteObjectCreated)                 \
128   fn(StructuralDexFileLoadHook, ArtJvmtiEvent::kStructuralDexFileLoadHook)
129 
130 template <ArtJvmtiEvent kEvent>
131 struct EventFnType {
132 };
133 
134 #define EVENT_FN_TYPE(name, enum_name)                    \
135 template <>                                               \
136 struct EventFnType<enum_name> {                           \
137   using type = decltype(ArtJvmtiEventCallbacks().name);   \
138 };
139 
140 FORALL_EVENT_TYPES(EVENT_FN_TYPE)
141 
142 #undef EVENT_FN_TYPE
143 
144 #define MAKE_EVENT_HANDLER_FUNC(name, enum_name)                                          \
145 template<>                                                                                \
146 struct EventHandlerFunc<enum_name> {                                                      \
147   using EventFnType = typename impl::EventFnType<enum_name>::type;                        \
148   explicit EventHandlerFunc(ArtJvmTiEnv* env)                                             \
149       : env_(env),                                                                        \
150         fn_(env_->event_callbacks == nullptr ? nullptr : env_->event_callbacks->name) { } \
151                                                                                           \
152   template <typename ...Args>                                                             \
153   ALWAYS_INLINE                                                                           \
154   void ExecuteCallback(JNIEnv* jnienv, Args... args) const {                              \
155     if (fn_ != nullptr) {                                                                 \
156       ScopedEventDispatchEnvironment sede(jnienv);                                        \
157       DoExecute(jnienv, args...);                                                         \
158     }                                                                                     \
159   }                                                                                       \
160                                                                                           \
161   template <typename ...Args>                                                             \
162   ALWAYS_INLINE                                                                           \
163   void ExecuteCallback(Args... args) const {                                              \
164     if (fn_ != nullptr) {                                                                 \
165       ScopedEventDispatchEnvironment sede;                                                \
166       DoExecute(args...);                                                                 \
167     }                                                                                     \
168   }                                                                                       \
169                                                                                           \
170  private:                                                                                 \
171   template <typename ...Args>                                                             \
172   ALWAYS_INLINE                                                                           \
173   inline void DoExecute(Args... args) const {                                             \
174     static_assert(std::is_same<EventFnType, void(*)(jvmtiEnv*, Args...)>::value,          \
175           "Unexpected different type of ExecuteCallback");                                \
176     fn_(env_, args...);                                                                   \
177   }                                                                                       \
178                                                                                           \
179  public:                                                                                  \
180   ArtJvmTiEnv* env_;                                                                      \
181   EventFnType fn_;                                                                        \
182 };
183 
184 FORALL_EVENT_TYPES(MAKE_EVENT_HANDLER_FUNC)
185 
186 #undef MAKE_EVENT_HANDLER_FUNC
187 
188 #undef FORALL_EVENT_TYPES
189 
190 }  // namespace impl
191 
192 template <ArtJvmtiEvent kEvent, typename ...Args>
CollectEvents(art::Thread * thread,Args...args)193 inline std::vector<impl::EventHandlerFunc<kEvent>> EventHandler::CollectEvents(art::Thread* thread,
194                                                                                Args... args) const {
195   art::ReaderMutexLock mu(thread, envs_lock_);
196   std::vector<impl::EventHandlerFunc<kEvent>> handlers;
197   for (ArtJvmTiEnv* env : envs) {
198     if (ShouldDispatch<kEvent>(env, thread, args...)) {
199       impl::EventHandlerFunc<kEvent> h(env);
200       handlers.push_back(h);
201     }
202   }
203   return handlers;
204 }
205 
206 // C++ does not allow partial template function specialization. The dispatch for our separated
207 // ClassFileLoadHook event types is the same, so use this helper for code deduplication.
208 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)209 inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
210                                                          JNIEnv* jnienv,
211                                                          jclass class_being_redefined,
212                                                          jobject loader,
213                                                          const char* name,
214                                                          jobject protection_domain,
215                                                          jint class_data_len,
216                                                          const unsigned char* class_data,
217                                                          jint* new_class_data_len,
218                                                          unsigned char** new_class_data) const {
219   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
220   static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
221                 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
222                 kEvent == ArtJvmtiEvent::kStructuralDexFileLoadHook, "Unsupported event");
223   DCHECK(*new_class_data == nullptr);
224   jint current_len = class_data_len;
225   unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
226   std::vector<impl::EventHandlerFunc<kEvent>> handlers =
227       CollectEvents<kEvent>(thread,
228                             jnienv,
229                             class_being_redefined,
230                             loader,
231                             name,
232                             protection_domain,
233                             class_data_len,
234                             class_data,
235                             new_class_data_len,
236                             new_class_data);
237   ArtJvmTiEnv* last_env = nullptr;
238   for (const impl::EventHandlerFunc<kEvent>& event : handlers) {
239     jint new_len = 0;
240     unsigned char* new_data = nullptr;
241     ExecuteCallback<kEvent>(event,
242                             jnienv,
243                             class_being_redefined,
244                             loader,
245                             name,
246                             protection_domain,
247                             current_len,
248                             static_cast<const unsigned char*>(current_class_data),
249                             &new_len,
250                             &new_data);
251     if (new_data != nullptr && new_data != current_class_data) {
252       // Destroy the data the last transformer made. We skip this if the previous state was the
253       // initial one since we don't know here which jvmtiEnv allocated it.
254       // NB Currently this doesn't matter since all allocations just go to malloc but in the
255       // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
256       if (last_env != nullptr) {
257         last_env->Deallocate(current_class_data);
258       }
259       last_env = event.env_;
260       current_class_data = new_data;
261       current_len = new_len;
262     }
263   }
264   if (last_env != nullptr) {
265     *new_class_data_len = current_len;
266     *new_class_data = current_class_data;
267   }
268 }
269 
270 // Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
271 // exactly the argument types of the corresponding Jvmti kEvent function pointer.
272 
273 template <ArtJvmtiEvent kEvent, typename ...Args>
DispatchEvent(art::Thread * thread,Args...args)274 inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
275   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
276   static_assert(!std::is_same<JNIEnv*,
277                               typename std::decay_t<
278                                   std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
279                 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
280   DCHECK(thread == nullptr || !thread->IsExceptionPending());
281   std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, args...);
282   for (auto event : events) {
283     ExecuteCallback<kEvent>(event, args...);
284   }
285 }
286 
287 template <ArtJvmtiEvent kEvent, typename ...Args>
DispatchEvent(art::Thread * thread,JNIEnv * jnienv,Args...args)288 inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
289   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
290   std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
291                                                                              jnienv,
292                                                                              args...);
293   for (auto event : events) {
294     ExecuteCallback<kEvent>(event, jnienv, args...);
295   }
296 }
297 
298 template <ArtJvmtiEvent kEvent, typename ...Args>
DispatchEventOnEnv(ArtJvmTiEnv * env,art::Thread * thread,JNIEnv * jnienv,Args...args)299 inline void EventHandler::DispatchEventOnEnv(
300     ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
301   DCHECK(env != nullptr);
302   if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
303     art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
304     impl::EventHandlerFunc<kEvent> func(env);
305     ExecuteCallback<kEvent>(func, jnienv, args...);
306   }
307 }
308 
309 template <ArtJvmtiEvent kEvent, typename ...Args>
DispatchEventOnEnv(ArtJvmTiEnv * env,art::Thread * thread,Args...args)310 inline void EventHandler::DispatchEventOnEnv(
311     ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
312   static_assert(!std::is_same<JNIEnv*,
313                               typename std::decay_t<
314                                   std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
315                 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
316   DCHECK(env != nullptr);
317   if (ShouldDispatch<kEvent, Args...>(env, thread, args...)) {
318     art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
319     impl::EventHandlerFunc<kEvent> func(env);
320     ExecuteCallback<kEvent>(func, args...);
321   }
322 }
323 
324 template <>
325 inline void EventHandler::DispatchEventOnEnv<ArtJvmtiEvent::kObsoleteObjectCreated>(
326     ArtJvmTiEnv* env, art::Thread* thread, jlong* obsolete_tag, jlong* new_tag) const {
327   static constexpr ArtJvmtiEvent kEvent = ArtJvmtiEvent::kObsoleteObjectCreated;
328   DCHECK(env != nullptr);
329   if (ShouldDispatch<kEvent>(env, thread, obsolete_tag, new_tag)) {
330     art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
331     impl::EventHandlerFunc<kEvent> func(env);
332     ExecuteCallback<kEvent>(func, obsolete_tag, new_tag);
333   } else {
334     // Unlike most others this has a default action to make sure that agents without knowledge of
335     // this extension get reasonable behavior.
336     jlong temp = *obsolete_tag;
337     *obsolete_tag = *new_tag;
338     *new_tag = temp;
339   }
340 }
341 
342 template <ArtJvmtiEvent kEvent, typename ...Args>
ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,Args...args)343 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
344   handler.ExecuteCallback(args...);
345 }
346 
347 template <ArtJvmtiEvent kEvent, typename ...Args>
ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,JNIEnv * jnienv,Args...args)348 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
349                                           JNIEnv* jnienv,
350                                           Args... args) {
351   handler.ExecuteCallback(jnienv, args...);
352 }
353 
354 // Events that need custom logic for if we send the event but are otherwise normal. This includes
355 // the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
356 
357 // Need to give custom specializations for Breakpoint since it needs to filter out which particular
358 // methods/dex_pcs agents get notified on.
359 template <>
360 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
361     ArtJvmTiEnv* env,
362     art::Thread* thread,
363     JNIEnv* jnienv ATTRIBUTE_UNUSED,
364     jthread jni_thread ATTRIBUTE_UNUSED,
365     jmethodID jmethod,
366     jlocation location) const {
367   art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
368   art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
369   return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
370       env->breakpoints.find({method, location}) != env->breakpoints.end();
371 }
372 
373 template <>
374 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
375     ArtJvmTiEnv* env,
376     art::Thread* thread,
377     JNIEnv* jnienv ATTRIBUTE_UNUSED,
378     jthread jni_thread ATTRIBUTE_UNUSED,
379     jmethodID jmethod ATTRIBUTE_UNUSED,
380     jboolean is_exception ATTRIBUTE_UNUSED,
381     const art::ShadowFrame* frame) const {
382   // Search for the frame. Do this before checking if we need to send the event so that we don't
383   // have to deal with use-after-free or the frames being reallocated later.
384   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
385   return env->notify_frames.erase(frame) != 0 &&
386       !frame->GetSkipMethodExitEvents() &&
387       ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
388 }
389 
390 // Need to give custom specializations for FieldAccess and FieldModification since they need to
391 // filter out which particular fields agents want to get notified on.
392 // TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
393 // could make the system more performant.
394 template <>
395 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
396     ArtJvmTiEnv* env,
397     art::Thread* thread,
398     JNIEnv* jnienv ATTRIBUTE_UNUSED,
399     jthread jni_thread ATTRIBUTE_UNUSED,
400     jmethodID method ATTRIBUTE_UNUSED,
401     jlocation location ATTRIBUTE_UNUSED,
402     jclass field_klass ATTRIBUTE_UNUSED,
403     jobject object ATTRIBUTE_UNUSED,
404     jfieldID field,
405     char type_char ATTRIBUTE_UNUSED,
406     jvalue val ATTRIBUTE_UNUSED) const {
407   art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
408   return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
409       env->modify_watched_fields.find(
410           art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
411 }
412 
413 template <>
414 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
415     ArtJvmTiEnv* env,
416     art::Thread* thread,
417     JNIEnv* jnienv ATTRIBUTE_UNUSED,
418     jthread jni_thread ATTRIBUTE_UNUSED,
419     jmethodID method ATTRIBUTE_UNUSED,
420     jlocation location ATTRIBUTE_UNUSED,
421     jclass field_klass ATTRIBUTE_UNUSED,
422     jobject object ATTRIBUTE_UNUSED,
423     jfieldID field) const {
424   art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
425   return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
426       env->access_watched_fields.find(
427           art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
428 }
429 
430 // Need to give custom specializations for FramePop since it needs to filter out which particular
431 // agents get the event. This specialization gets an extra argument so we can determine which (if
432 // any) environments have the frame pop.
433 // TODO It might be useful to use more template magic to have this only define ShouldDispatch or
434 // something.
435 template <>
436 inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
437     impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
438     JNIEnv* jnienv,
439     jthread jni_thread,
440     jmethodID jmethod,
441     jboolean is_exception,
442     const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
443   ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
444 }
445 
446 struct ScopedDisablePopFrame {
447  public:
ScopedDisablePopFrameScopedDisablePopFrame448   explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) {
449     art::Locks::mutator_lock_->AssertSharedHeld(thread_);
450     art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
451     JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_);
452     current_top_frame_ = art::StackVisitor::ComputeNumFrames(
453         thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
454     old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
455     data->disable_pop_frame_depth = current_top_frame_;
456     // Check that we cleaned up any old disables. This should only increase (or be equals if we do
457     // another ClassLoad/Prepare recursively).
458     DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
459            current_top_frame_ >= old_disable_frame_pop_depth_)
460         << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
461   }
462 
~ScopedDisablePopFrameScopedDisablePopFrame463   ~ScopedDisablePopFrame() {
464     art::Locks::mutator_lock_->AssertSharedHeld(thread_);
465     art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
466     JvmtiGlobalTLSData* data = ThreadUtil::GetGlobalTLSData(thread_);
467     DCHECK_EQ(data->disable_pop_frame_depth, current_top_frame_);
468     data->disable_pop_frame_depth = old_disable_frame_pop_depth_;
469   }
470 
471  private:
472   art::Thread* thread_;
473   size_t current_top_frame_;
474   size_t old_disable_frame_pop_depth_;
475 };
476 // We want to prevent the use of PopFrame when reporting either of these events.
477 template <ArtJvmtiEvent kEvent>
DispatchClassLoadOrPrepareEvent(art::Thread * thread,JNIEnv * jnienv,jthread jni_thread,jclass klass)478 inline void EventHandler::DispatchClassLoadOrPrepareEvent(art::Thread* thread,
479                                                           JNIEnv* jnienv,
480                                                           jthread jni_thread,
481                                                           jclass klass) const {
482   ScopedDisablePopFrame sdpf(thread);
483   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
484   std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
485                                                                              jnienv,
486                                                                              jni_thread,
487                                                                              klass);
488 
489   for (auto event : events) {
490     ExecuteCallback<kEvent>(event, jnienv, jni_thread, klass);
491   }
492 }
493 
494 template <>
495 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassLoad>(art::Thread* thread,
496                                                                    JNIEnv* jnienv,
497                                                                    jthread jni_thread,
498                                                                    jclass klass) const {
499   DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassLoad>(thread, jnienv, jni_thread, klass);
500 }
501 template <>
502 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassPrepare>(art::Thread* thread,
503                                                                       JNIEnv* jnienv,
504                                                                       jthread jni_thread,
505                                                                       jclass klass) const {
506   DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassPrepare>(thread, jnienv, jni_thread, klass);
507 }
508 
509 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out
510 // variable.
511 template <>
512 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
513                                                                           JNIEnv* jnienv,
514                                                                           jthread jni_thread,
515                                                                           jmethodID method,
516                                                                           void* cur_method,
517                                                                           void** new_method) const {
518   art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
519   std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
520       CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
521                                                       jnienv,
522                                                       jni_thread,
523                                                       method,
524                                                       cur_method,
525                                                       new_method);
526   *new_method = cur_method;
527   for (auto event : events) {
528     *new_method = cur_method;
529     ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
530                                                       jnienv,
531                                                       jni_thread,
532                                                       method,
533                                                       cur_method,
534                                                       new_method);
535     if (*new_method != nullptr) {
536       cur_method = *new_method;
537     }
538   }
539   *new_method = cur_method;
540 }
541 
542 // C++ does not allow partial template function specialization. The dispatch for our separated
543 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
544 // The following two DispatchEvent specializations dispatch to it.
545 template <>
546 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
547     art::Thread* thread,
548     JNIEnv* jnienv,
549     jclass class_being_redefined,
550     jobject loader,
551     const char* name,
552     jobject protection_domain,
553     jint class_data_len,
554     const unsigned char* class_data,
555     jint* new_class_data_len,
556     unsigned char** new_class_data) const {
557   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
558       thread,
559       jnienv,
560       class_being_redefined,
561       loader,
562       name,
563       protection_domain,
564       class_data_len,
565       class_data,
566       new_class_data_len,
567       new_class_data);
568 }
569 
570 template <>
571 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
572     art::Thread* thread,
573     JNIEnv* jnienv,
574     jclass class_being_redefined,
575     jobject loader,
576     const char* name,
577     jobject protection_domain,
578     jint class_data_len,
579     const unsigned char* class_data,
580     jint* new_class_data_len,
581     unsigned char** new_class_data) const {
582   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
583       thread,
584       jnienv,
585       class_being_redefined,
586       loader,
587       name,
588       protection_domain,
589       class_data_len,
590       class_data,
591       new_class_data_len,
592       new_class_data);
593 }
594 
595 template <>
596 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
597     art::Thread* thread,
598     JNIEnv* jnienv,
599     jclass class_being_redefined,
600     jobject loader,
601     const char* name,
602     jobject protection_domain,
603     jint class_data_len,
604     const unsigned char* class_data,
605     jint* new_class_data_len,
606     unsigned char** new_class_data) const {
607   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
608       thread,
609       jnienv,
610       class_being_redefined,
611       loader,
612       name,
613       protection_domain,
614       class_data_len,
615       class_data,
616       new_class_data_len,
617       new_class_data);
618 }
619 
620 template <ArtJvmtiEvent kEvent>
ShouldDispatchOnThread(ArtJvmTiEnv * env,art::Thread * thread)621 inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const {
622   bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
623 
624   if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
625     EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
626     dispatch = mask != nullptr && mask->Test(kEvent);
627   }
628   return dispatch;
629 }
630 
631 template <ArtJvmtiEvent kEvent, typename ...Args>
ShouldDispatch(ArtJvmTiEnv * env,art::Thread * thread,Args...args ATTRIBUTE_UNUSED)632 inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
633                                          art::Thread* thread,
634                                          Args... args ATTRIBUTE_UNUSED) const {
635   static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
636                              void(*)(jvmtiEnv*, Args...)>::value,
637                 "Unexpected different type of shouldDispatch");
638 
639   return ShouldDispatchOnThread<kEvent>(env, thread);
640 }
641 
RecalculateGlobalEventMask(ArtJvmtiEvent event)642 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
643   art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
644   RecalculateGlobalEventMaskLocked(event);
645 }
646 
RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event)647 inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) {
648   bool union_value = false;
649   for (const ArtJvmTiEnv* stored_env : envs) {
650     if (stored_env == nullptr) {
651       continue;
652     }
653     union_value |= stored_env->event_masks.global_event_mask.Test(event);
654     union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
655     if (union_value) {
656       break;
657     }
658   }
659   global_mask.Set(event, union_value);
660 }
661 
NeedsEventUpdate(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)662 inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
663                                            const jvmtiCapabilities& caps,
664                                            bool added) {
665   ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
666                               : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
667   return (added && caps.can_access_local_variables == 1) ||
668       caps.can_generate_breakpoint_events == 1 ||
669       caps.can_pop_frame == 1 ||
670       caps.can_force_early_return == 1 ||
671       (caps.can_retransform_classes == 1 &&
672        IsEventEnabledAnywhere(event) &&
673        env->event_masks.IsEnabledAnywhere(event));
674 }
675 
HandleChangedCapabilities(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)676 inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
677                                                     const jvmtiCapabilities& caps,
678                                                     bool added) {
679   if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
680     env->event_masks.HandleChangedCapabilities(caps, added);
681     if (caps.can_retransform_classes == 1) {
682       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
683       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
684     }
685     if (added && caps.can_access_local_variables == 1) {
686       HandleLocalAccessCapabilityAdded();
687     }
688     if (caps.can_generate_breakpoint_events == 1) {
689       HandleBreakpointEventsChanged(added);
690     }
691     if ((caps.can_pop_frame == 1 || caps.can_force_early_return == 1) && added) {
692       // TODO We should keep track of how many of these have been enabled and remove it if there are
693       // no more possible users. This isn't expected to be too common.
694       art::Runtime::Current()->SetNonStandardExitsEnabled();
695     }
696   }
697 }
698 
699 }  // namespace openjdkjvmti
700 
701 #endif  // ART_OPENJDKJVMTI_EVENTS_INL_H_
702