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
364 [[maybe_unused]] JNIEnv* jnienv,
365 [[maybe_unused]] jthread jni_thread,
366 jmethodID jmethod,
367 jlocation location) const {
368 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
369 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
370 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
371 env->breakpoints.find({method, location}) != env->breakpoints.end();
372 }
373
374 template <>
375 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
376 ArtJvmTiEnv* env,
377 art::Thread* thread,
378 [[maybe_unused]] JNIEnv* jnienv,
379 [[maybe_unused]] jthread jni_thread,
380 [[maybe_unused]] jmethodID jmethod,
381 [[maybe_unused]] jboolean is_exception,
382 const art::ShadowFrame* frame) const {
383 // Search for the frame. Do this before checking if we need to send the event so that we don't
384 // have to deal with use-after-free or the frames being reallocated later.
385 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
386 return env->notify_frames.erase(frame) != 0 &&
387 !frame->GetSkipMethodExitEvents() &&
388 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
389 }
390
391 // Need to give custom specializations for FieldAccess and FieldModification since they need to
392 // filter out which particular fields agents want to get notified on.
393 // TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
394 // could make the system more performant.
395 template <>
396 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
397 ArtJvmTiEnv* env,
398 art::Thread* thread,
399 [[maybe_unused]] JNIEnv* jnienv,
400 [[maybe_unused]] jthread jni_thread,
401 [[maybe_unused]] jmethodID method,
402 [[maybe_unused]] jlocation location,
403 [[maybe_unused]] jclass field_klass,
404 [[maybe_unused]] jobject object,
405 jfieldID field,
406 [[maybe_unused]] char type_char,
407 [[maybe_unused]] jvalue val) const {
408 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
409 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
410 env->modify_watched_fields.find(
411 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
412 }
413
414 template <>
415 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
416 ArtJvmTiEnv* env,
417 art::Thread* thread,
418 [[maybe_unused]] JNIEnv* jnienv,
419 [[maybe_unused]] jthread jni_thread,
420 [[maybe_unused]] jmethodID method,
421 [[maybe_unused]] jlocation location,
422 [[maybe_unused]] jclass field_klass,
423 [[maybe_unused]] jobject object,
424 jfieldID field) const {
425 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
426 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
427 env->access_watched_fields.find(
428 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
429 }
430
431 // Need to give custom specializations for FramePop since it needs to filter out which particular
432 // agents get the event. This specialization gets an extra argument so we can determine which (if
433 // any) environments have the frame pop.
434 // TODO It might be useful to use more template magic to have this only define ShouldDispatch or
435 // something.
436 template <>
437 inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
438 impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
439 JNIEnv* jnienv,
440 jthread jni_thread,
441 jmethodID jmethod,
442 jboolean is_exception,
443 [[maybe_unused]] const art::ShadowFrame* frame) {
444 ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
445 }
446
447 struct ScopedDisablePopFrame {
448 public:
ScopedDisablePopFrameScopedDisablePopFrame449 explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) {
450 art::Locks::mutator_lock_->AssertSharedHeld(thread_);
451 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
452 JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_);
453 current_top_frame_ = art::StackVisitor::ComputeNumFrames(
454 thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
455 old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
456 data->disable_pop_frame_depth = current_top_frame_;
457 // Check that we cleaned up any old disables. This should only increase (or be equals if we do
458 // another ClassLoad/Prepare recursively).
459 DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
460 current_top_frame_ >= old_disable_frame_pop_depth_)
461 << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
462 }
463
~ScopedDisablePopFrameScopedDisablePopFrame464 ~ScopedDisablePopFrame() {
465 art::Locks::mutator_lock_->AssertSharedHeld(thread_);
466 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
467 JvmtiGlobalTLSData* data = ThreadUtil::GetGlobalTLSData(thread_);
468 DCHECK_EQ(data->disable_pop_frame_depth, current_top_frame_);
469 data->disable_pop_frame_depth = old_disable_frame_pop_depth_;
470 }
471
472 private:
473 art::Thread* thread_;
474 size_t current_top_frame_;
475 size_t old_disable_frame_pop_depth_;
476 };
477 // We want to prevent the use of PopFrame when reporting either of these events.
478 template <ArtJvmtiEvent kEvent>
DispatchClassLoadOrPrepareEvent(art::Thread * thread,JNIEnv * jnienv,jthread jni_thread,jclass klass)479 inline void EventHandler::DispatchClassLoadOrPrepareEvent(art::Thread* thread,
480 JNIEnv* jnienv,
481 jthread jni_thread,
482 jclass klass) const {
483 ScopedDisablePopFrame sdpf(thread);
484 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
485 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
486 jnienv,
487 jni_thread,
488 klass);
489
490 for (auto event : events) {
491 ExecuteCallback<kEvent>(event, jnienv, jni_thread, klass);
492 }
493 }
494
495 template <>
496 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassLoad>(art::Thread* thread,
497 JNIEnv* jnienv,
498 jthread jni_thread,
499 jclass klass) const {
500 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassLoad>(thread, jnienv, jni_thread, klass);
501 }
502 template <>
503 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassPrepare>(art::Thread* thread,
504 JNIEnv* jnienv,
505 jthread jni_thread,
506 jclass klass) const {
507 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassPrepare>(thread, jnienv, jni_thread, klass);
508 }
509
510 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out
511 // variable.
512 template <>
513 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
514 JNIEnv* jnienv,
515 jthread jni_thread,
516 jmethodID method,
517 void* cur_method,
518 void** new_method) const {
519 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
520 std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
521 CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
522 jnienv,
523 jni_thread,
524 method,
525 cur_method,
526 new_method);
527 *new_method = cur_method;
528 for (auto event : events) {
529 *new_method = cur_method;
530 ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
531 jnienv,
532 jni_thread,
533 method,
534 cur_method,
535 new_method);
536 if (*new_method != nullptr) {
537 cur_method = *new_method;
538 }
539 }
540 *new_method = cur_method;
541 }
542
543 // C++ does not allow partial template function specialization. The dispatch for our separated
544 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
545 // The following two DispatchEvent specializations dispatch to it.
546 template <>
547 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
548 art::Thread* thread,
549 JNIEnv* jnienv,
550 jclass class_being_redefined,
551 jobject loader,
552 const char* name,
553 jobject protection_domain,
554 jint class_data_len,
555 const unsigned char* class_data,
556 jint* new_class_data_len,
557 unsigned char** new_class_data) const {
558 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
559 thread,
560 jnienv,
561 class_being_redefined,
562 loader,
563 name,
564 protection_domain,
565 class_data_len,
566 class_data,
567 new_class_data_len,
568 new_class_data);
569 }
570
571 template <>
572 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
573 art::Thread* thread,
574 JNIEnv* jnienv,
575 jclass class_being_redefined,
576 jobject loader,
577 const char* name,
578 jobject protection_domain,
579 jint class_data_len,
580 const unsigned char* class_data,
581 jint* new_class_data_len,
582 unsigned char** new_class_data) const {
583 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
584 thread,
585 jnienv,
586 class_being_redefined,
587 loader,
588 name,
589 protection_domain,
590 class_data_len,
591 class_data,
592 new_class_data_len,
593 new_class_data);
594 }
595
596 template <>
597 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
598 art::Thread* thread,
599 JNIEnv* jnienv,
600 jclass class_being_redefined,
601 jobject loader,
602 const char* name,
603 jobject protection_domain,
604 jint class_data_len,
605 const unsigned char* class_data,
606 jint* new_class_data_len,
607 unsigned char** new_class_data) const {
608 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
609 thread,
610 jnienv,
611 class_being_redefined,
612 loader,
613 name,
614 protection_domain,
615 class_data_len,
616 class_data,
617 new_class_data_len,
618 new_class_data);
619 }
620
621 template <ArtJvmtiEvent kEvent>
ShouldDispatchOnThread(ArtJvmTiEnv * env,art::Thread * thread)622 inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const {
623 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
624
625 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
626 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
627 dispatch = mask != nullptr && mask->Test(kEvent);
628 }
629 return dispatch;
630 }
631
632 template <ArtJvmtiEvent kEvent, typename... Args>
ShouldDispatch(ArtJvmTiEnv * env,art::Thread * thread,Args...args)633 inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
634 art::Thread* thread,
635 [[maybe_unused]] Args... args) const {
636 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
637 void(*)(jvmtiEnv*, Args...)>::value,
638 "Unexpected different type of shouldDispatch");
639
640 return ShouldDispatchOnThread<kEvent>(env, thread);
641 }
642
RecalculateGlobalEventMask(ArtJvmtiEvent event)643 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
644 art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
645 RecalculateGlobalEventMaskLocked(event);
646 }
647
RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event)648 inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) {
649 bool union_value = false;
650 for (const ArtJvmTiEnv* stored_env : envs) {
651 if (stored_env == nullptr) {
652 continue;
653 }
654 union_value |= stored_env->event_masks.global_event_mask.Test(event);
655 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
656 if (union_value) {
657 break;
658 }
659 }
660 global_mask.Set(event, union_value);
661 }
662
NeedsEventUpdate(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)663 inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
664 const jvmtiCapabilities& caps,
665 bool added) {
666 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
667 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
668 return (added && caps.can_access_local_variables == 1) ||
669 caps.can_generate_breakpoint_events == 1 ||
670 caps.can_pop_frame == 1 ||
671 caps.can_force_early_return == 1 ||
672 (caps.can_retransform_classes == 1 &&
673 IsEventEnabledAnywhere(event) &&
674 env->event_masks.IsEnabledAnywhere(event));
675 }
676
HandleChangedCapabilities(ArtJvmTiEnv * env,const jvmtiCapabilities & caps,bool added)677 inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
678 const jvmtiCapabilities& caps,
679 bool added) {
680 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
681 env->event_masks.HandleChangedCapabilities(caps, added);
682 if (caps.can_retransform_classes == 1) {
683 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
684 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
685 }
686 if (added && caps.can_access_local_variables == 1) {
687 HandleLocalAccessCapabilityAdded();
688 }
689 if (caps.can_generate_breakpoint_events == 1) {
690 HandleBreakpointEventsChanged(added);
691 }
692 if ((caps.can_pop_frame == 1 || caps.can_force_early_return == 1) && added) {
693 // TODO We should keep track of how many of these have been enabled and remove it if there are
694 // no more possible users. This isn't expected to be too common.
695 art::Runtime::Current()->SetNonStandardExitsEnabled();
696 }
697 }
698 }
699
700 } // namespace openjdkjvmti
701
702 #endif // ART_OPENJDKJVMTI_EVENTS_INL_H_
703