blob: d97916fa0a738059f6e2e4d019ddc5ba4db872ee [file] [log] [blame]
Andreas Gampe77708d92016-10-07 11:48:21 -07001/*
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
Andreas Gampe06c42a52017-07-26 14:17:14 -070017#ifndef ART_OPENJDKJVMTI_EVENTS_INL_H_
18#define ART_OPENJDKJVMTI_EVENTS_INL_H_
Andreas Gampe77708d92016-10-07 11:48:21 -070019
Alex Light73afd322017-01-18 11:17:47 -080020#include <array>
Alex Light9df79b72017-09-12 08:57:31 -070021#include <type_traits>
22#include <tuple>
Alex Light73afd322017-01-18 11:17:47 -080023
Alex Lightb6106d52017-10-18 15:02:15 -070024#include "base/mutex-inl.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070025#include "events.h"
Alex Light084fa372017-06-16 08:58:34 -070026#include "jni_internal.h"
Andreas Gampe373a9b52017-10-18 09:01:57 -070027#include "nativehelper/scoped_local_ref.h"
Alex Light9df79b72017-09-12 08:57:31 -070028#include "scoped_thread_state_change-inl.h"
Alex Lighta26e3492017-06-27 17:55:37 -070029#include "ti_breakpoint.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070030
31#include "art_jvmti.h"
32
33namespace openjdkjvmti {
34
Alex Light73afd322017-01-18 11:17:47 -080035static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
36 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
37 if (env->capabilities.can_retransform_classes) {
38 return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
39 } else {
40 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
41 }
42 } else {
43 return static_cast<ArtJvmtiEvent>(e);
44 }
Alex Light40d87f42017-01-18 10:27:06 -080045}
46
Andreas Gampe983c1752017-01-23 19:46:56 -080047namespace impl {
Andreas Gampe77708d92016-10-07 11:48:21 -070048
Andreas Gampe983c1752017-01-23 19:46:56 -080049// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070050
Andreas Gampe983c1752017-01-23 19:46:56 -080051#define FORALL_EVENT_TYPES(fn) \
52 fn(VMInit, ArtJvmtiEvent::kVmInit) \
53 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
54 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
55 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
56 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
57 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
58 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
59 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
60 fn(VMStart, ArtJvmtiEvent::kVmStart) \
61 fn(Exception, ArtJvmtiEvent::kException) \
62 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
63 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
64 fn(FramePop, ArtJvmtiEvent::kFramePop) \
65 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
66 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
67 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
68 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
69 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
70 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
71 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
72 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
73 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
74 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
75 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
76 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
77 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
78 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
79 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
80 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
81 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
82 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
83 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc)
84
85template <ArtJvmtiEvent kEvent>
86struct EventFnType {
87};
88
89#define EVENT_FN_TYPE(name, enum_name) \
90template <> \
91struct EventFnType<enum_name> { \
92 using type = decltype(jvmtiEventCallbacks().name); \
93};
94
95FORALL_EVENT_TYPES(EVENT_FN_TYPE)
96
97#undef EVENT_FN_TYPE
98
99template <ArtJvmtiEvent kEvent>
100ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
101
102#define GET_CALLBACK(name, enum_name) \
103template <> \
104ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
105 ArtJvmTiEnv* env) { \
106 if (env->event_callbacks == nullptr) { \
107 return nullptr; \
108 } \
109 return env->event_callbacks->name; \
Andreas Gampe77708d92016-10-07 11:48:21 -0700110}
111
Andreas Gampe983c1752017-01-23 19:46:56 -0800112FORALL_EVENT_TYPES(GET_CALLBACK)
Alex Light6ac57502017-01-19 15:05:06 -0800113
Andreas Gampe983c1752017-01-23 19:46:56 -0800114#undef GET_CALLBACK
115
116#undef FORALL_EVENT_TYPES
117
118} // namespace impl
119
120// C++ does not allow partial template function specialization. The dispatch for our separated
121// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Andreas Gampe983c1752017-01-23 19:46:56 -0800122template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800123inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800124 JNIEnv* jnienv,
125 jclass class_being_redefined,
126 jobject loader,
127 const char* name,
128 jobject protection_domain,
129 jint class_data_len,
130 const unsigned char* class_data,
131 jint* new_class_data_len,
132 unsigned char** new_class_data) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800133 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
134 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700135 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800136 jint current_len = class_data_len;
137 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
138 ArtJvmTiEnv* last_env = nullptr;
139 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700140 if (env == nullptr) {
141 continue;
142 }
Alex Light9df79b72017-09-12 08:57:31 -0700143 jint new_len = 0;
144 unsigned char* new_data = nullptr;
145 DispatchEventOnEnv<kEvent>(env,
146 thread,
147 jnienv,
148 class_being_redefined,
149 loader,
150 name,
151 protection_domain,
152 current_len,
153 static_cast<const unsigned char*>(current_class_data),
154 &new_len,
155 &new_data);
156 if (new_data != nullptr && new_data != current_class_data) {
157 // Destroy the data the last transformer made. We skip this if the previous state was the
158 // initial one since we don't know here which jvmtiEnv allocated it.
159 // NB Currently this doesn't matter since all allocations just go to malloc but in the
160 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
161 if (last_env != nullptr) {
162 last_env->Deallocate(current_class_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700163 }
Alex Light9df79b72017-09-12 08:57:31 -0700164 last_env = env;
165 current_class_data = new_data;
166 current_len = new_len;
Alex Light6ac57502017-01-19 15:05:06 -0800167 }
168 }
169 if (last_env != nullptr) {
170 *new_class_data_len = current_len;
171 *new_class_data = current_class_data;
172 }
173}
174
Andreas Gampe983c1752017-01-23 19:46:56 -0800175// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
176// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800177
Andreas Gampe983c1752017-01-23 19:46:56 -0800178template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700179inline void EventHandler::ExecuteCallback(ArtJvmTiEnv* env, Args... args) {
180 using FnType = typename impl::EventFnType<kEvent>::type;
181 FnType callback = impl::GetCallback<kEvent>(env);
182 if (callback != nullptr) {
183 (*callback)(env, args...);
184 }
185}
186
187template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700188inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Alex Light9df79b72017-09-12 08:57:31 -0700189 static_assert(!std::is_same<JNIEnv*,
190 typename std::decay_t<
191 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
192 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
193 DCHECK(thread == nullptr || !thread->IsExceptionPending());
Andreas Gampe77708d92016-10-07 11:48:21 -0700194 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700195 if (env != nullptr) {
Alex Light9df79b72017-09-12 08:57:31 -0700196 DispatchEventOnEnv<kEvent, Args...>(env, thread, args...);
Alex Lightbb766462017-04-12 16:13:33 -0700197 }
Andreas Gampea1705ea2017-03-28 20:12:13 -0700198 }
199}
200
Alex Light9df79b72017-09-12 08:57:31 -0700201// Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash
202// pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI
203// specification we allow exceptions originating from events to overwrite the current exception,
204// including exceptions originating from earlier events.
205class ScopedEventDispatchEnvironment FINAL : public art::ValueObject {
206 public:
207 explicit ScopedEventDispatchEnvironment(JNIEnv* env)
208 : env_(env),
209 thr_(env_, env_->ExceptionOccurred()),
210 suspend_(art::Thread::Current(), art::kNative) {
211 // The spec doesn't say how much local data should be there, so we just give 128 which seems
212 // likely to be enough for most cases.
213 env_->PushLocalFrame(128);
214 env_->ExceptionClear();
215 UNUSED(suspend_);
216 }
217
218 ~ScopedEventDispatchEnvironment() {
219 if (thr_.get() != nullptr && !env_->ExceptionCheck()) {
220 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
221 // of the newest exception.
222 env_->Throw(thr_.get());
223 }
224 env_->PopLocalFrame(nullptr);
225 }
226
227 private:
228 JNIEnv* env_;
229 ScopedLocalRef<jthrowable> thr_;
230 // Not actually unused. The destructor/constructor does important work.
231 art::ScopedThreadStateChange suspend_;
232
233 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
234};
235
Alex Lightb7edcda2017-04-27 13:20:31 -0700236template <ArtJvmtiEvent kEvent, typename ...Args>
237inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
238 for (ArtJvmTiEnv* env : envs) {
239 if (env != nullptr) {
Alex Light9df79b72017-09-12 08:57:31 -0700240 DispatchEventOnEnv<kEvent, Args...>(env, thread, jnienv, args...);
Alex Lightb7edcda2017-04-27 13:20:31 -0700241 }
242 }
243}
244
Andreas Gampea1705ea2017-03-28 20:12:13 -0700245template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700246inline void EventHandler::DispatchEventOnEnv(
247 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
248 DCHECK(env != nullptr);
249 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
250 ScopedEventDispatchEnvironment sede(jnienv);
251 ExecuteCallback<kEvent, JNIEnv*, Args...>(env, jnienv, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700252 }
253}
254
Alex Light9df79b72017-09-12 08:57:31 -0700255template <ArtJvmtiEvent kEvent, typename ...Args>
256inline void EventHandler::DispatchEventOnEnv(
257 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
258 static_assert(!std::is_same<JNIEnv*,
259 typename std::decay_t<
260 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
261 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
262 if (ShouldDispatch<kEvent>(env, thread, args...)) {
263 ExecuteCallback<kEvent, Args...>(env, args...);
264 }
265}
266
267// Events that need custom logic for if we send the event but are otherwise normal. This includes
268// the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
269
Alex Lighta26e3492017-06-27 17:55:37 -0700270// Need to give custom specializations for Breakpoint since it needs to filter out which particular
271// methods/dex_pcs agents get notified on.
272template <>
Alex Light9df79b72017-09-12 08:57:31 -0700273inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
274 ArtJvmTiEnv* env,
275 art::Thread* thread,
276 JNIEnv* jnienv ATTRIBUTE_UNUSED,
277 jthread jni_thread ATTRIBUTE_UNUSED,
278 jmethodID jmethod,
279 jlocation location) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700280 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Lighta26e3492017-06-27 17:55:37 -0700281 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
Alex Light9df79b72017-09-12 08:57:31 -0700282 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
283 env->breakpoints.find({method, location}) != env->breakpoints.end();
Alex Lighta26e3492017-06-27 17:55:37 -0700284}
285
Alex Lighte814f9d2017-07-31 16:14:39 -0700286template <>
Alex Light9df79b72017-09-12 08:57:31 -0700287inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
288 ArtJvmTiEnv* env,
Alex Lighte814f9d2017-07-31 16:14:39 -0700289 art::Thread* thread,
Alex Light9df79b72017-09-12 08:57:31 -0700290 JNIEnv* jnienv ATTRIBUTE_UNUSED,
291 jthread jni_thread ATTRIBUTE_UNUSED,
292 jmethodID jmethod ATTRIBUTE_UNUSED,
293 jboolean is_exception ATTRIBUTE_UNUSED,
Alex Lighte814f9d2017-07-31 16:14:39 -0700294 const art::ShadowFrame* frame) const {
Alex Light9df79b72017-09-12 08:57:31 -0700295 // Search for the frame. Do this before checking if we need to send the event so that we don't
296 // have to deal with use-after-free or the frames being reallocated later.
Alex Lightb6106d52017-10-18 15:02:15 -0700297 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700298 return env->notify_frames.erase(frame) != 0 &&
299 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
Alex Lighte814f9d2017-07-31 16:14:39 -0700300}
301
Alex Light084fa372017-06-16 08:58:34 -0700302// Need to give custom specializations for FieldAccess and FieldModification since they need to
303// filter out which particular fields agents want to get notified on.
304// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
305// could make the system more performant.
306template <>
Alex Light9df79b72017-09-12 08:57:31 -0700307inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
308 ArtJvmTiEnv* env,
309 art::Thread* thread,
310 JNIEnv* jnienv ATTRIBUTE_UNUSED,
311 jthread jni_thread ATTRIBUTE_UNUSED,
312 jmethodID method ATTRIBUTE_UNUSED,
313 jlocation location ATTRIBUTE_UNUSED,
314 jclass field_klass ATTRIBUTE_UNUSED,
315 jobject object ATTRIBUTE_UNUSED,
316 jfieldID field,
317 char type_char ATTRIBUTE_UNUSED,
318 jvalue val ATTRIBUTE_UNUSED) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700319 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700320 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
321 env->modify_watched_fields.find(
322 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
Alex Light084fa372017-06-16 08:58:34 -0700323}
324
325template <>
Alex Light9df79b72017-09-12 08:57:31 -0700326inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
327 ArtJvmTiEnv* env,
328 art::Thread* thread,
329 JNIEnv* jnienv ATTRIBUTE_UNUSED,
330 jthread jni_thread ATTRIBUTE_UNUSED,
331 jmethodID method ATTRIBUTE_UNUSED,
332 jlocation location ATTRIBUTE_UNUSED,
333 jclass field_klass ATTRIBUTE_UNUSED,
334 jobject object ATTRIBUTE_UNUSED,
335 jfieldID field) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700336 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700337 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
338 env->access_watched_fields.find(
339 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
340}
341
342// Need to give custom specializations for FramePop since it needs to filter out which particular
343// agents get the event. This specialization gets an extra argument so we can determine which (if
344// any) environments have the frame pop.
345// TODO It might be useful to use more template magic to have this only define ShouldDispatch or
346// something.
347template <>
348inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
349 ArtJvmTiEnv* env,
350 JNIEnv* jnienv,
351 jthread jni_thread,
352 jmethodID jmethod,
353 jboolean is_exception,
354 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
355 ExecuteCallback<ArtJvmtiEvent::kFramePop>(
356 env, jnienv, jni_thread, jmethod, is_exception);
Alex Light084fa372017-06-16 08:58:34 -0700357}
358
Alex Lightd78ddec2017-04-18 15:20:38 -0700359// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
360// variable.
361template <>
362inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
363 JNIEnv* jnienv,
364 jthread jni_thread,
365 jmethodID method,
366 void* cur_method,
367 void** new_method) const {
368 *new_method = cur_method;
369 for (ArtJvmTiEnv* env : envs) {
Alex Light9df79b72017-09-12 08:57:31 -0700370 if (env != nullptr) {
371 *new_method = cur_method;
372 DispatchEventOnEnv<ArtJvmtiEvent::kNativeMethodBind>(env,
373 thread,
374 jnienv,
375 jni_thread,
376 method,
377 cur_method,
378 new_method);
Alex Lightd78ddec2017-04-18 15:20:38 -0700379 if (*new_method != nullptr) {
380 cur_method = *new_method;
381 }
382 }
383 }
Alex Light9df79b72017-09-12 08:57:31 -0700384 *new_method = cur_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700385}
386
Andreas Gampe983c1752017-01-23 19:46:56 -0800387// C++ does not allow partial template function specialization. The dispatch for our separated
388// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
389// The following two DispatchEvent specializations dispatch to it.
390template <>
391inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
392 art::Thread* thread,
393 JNIEnv* jnienv,
394 jclass class_being_redefined,
395 jobject loader,
396 const char* name,
397 jobject protection_domain,
398 jint class_data_len,
399 const unsigned char* class_data,
400 jint* new_class_data_len,
401 unsigned char** new_class_data) const {
402 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
403 thread,
404 jnienv,
405 class_being_redefined,
406 loader,
407 name,
408 protection_domain,
409 class_data_len,
410 class_data,
411 new_class_data_len,
412 new_class_data);
413}
Alex Light9df79b72017-09-12 08:57:31 -0700414
Andreas Gampe983c1752017-01-23 19:46:56 -0800415template <>
416inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
417 art::Thread* thread,
418 JNIEnv* jnienv,
419 jclass class_being_redefined,
420 jobject loader,
421 const char* name,
422 jobject protection_domain,
423 jint class_data_len,
424 const unsigned char* class_data,
425 jint* new_class_data_len,
426 unsigned char** new_class_data) const {
427 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
428 thread,
429 jnienv,
430 class_being_redefined,
431 loader,
432 name,
433 protection_domain,
434 class_data_len,
435 class_data,
436 new_class_data_len,
437 new_class_data);
438}
Alex Light40d87f42017-01-18 10:27:06 -0800439
Andreas Gampe983c1752017-01-23 19:46:56 -0800440template <ArtJvmtiEvent kEvent>
Alex Light9df79b72017-09-12 08:57:31 -0700441inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) {
Andreas Gampe983c1752017-01-23 19:46:56 -0800442 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
443
444 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800445 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800446 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800447 }
448 return dispatch;
449}
450
Alex Light9df79b72017-09-12 08:57:31 -0700451template <ArtJvmtiEvent kEvent, typename ...Args>
452inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
453 art::Thread* thread,
454 Args... args ATTRIBUTE_UNUSED) const {
455 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
456 void(*)(jvmtiEnv*, Args...)>::value,
457 "Unexpected different type of shouldDispatch");
458
459 return ShouldDispatchOnThread<kEvent>(env, thread);
460}
461
Alex Light73afd322017-01-18 11:17:47 -0800462inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
463 bool union_value = false;
464 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700465 if (stored_env == nullptr) {
466 continue;
467 }
Alex Light73afd322017-01-18 11:17:47 -0800468 union_value |= stored_env->event_masks.global_event_mask.Test(event);
469 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
470 if (union_value) {
471 break;
472 }
473 }
474 global_mask.Set(event, union_value);
475}
476
477inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
478 const jvmtiCapabilities& caps,
479 bool added) {
480 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
481 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700482 return (added && caps.can_access_local_variables == 1) ||
483 (caps.can_retransform_classes == 1 &&
484 IsEventEnabledAnywhere(event) &&
485 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800486}
487
488inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
489 const jvmtiCapabilities& caps,
490 bool added) {
491 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
492 env->event_masks.HandleChangedCapabilities(caps, added);
493 if (caps.can_retransform_classes == 1) {
494 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
495 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
496 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700497 if (added && caps.can_access_local_variables == 1) {
498 HandleLocalAccessCapabilityAdded();
499 }
Alex Light73afd322017-01-18 11:17:47 -0800500 }
501}
502
Andreas Gampe77708d92016-10-07 11:48:21 -0700503} // namespace openjdkjvmti
504
Andreas Gampe06c42a52017-07-26 14:17:14 -0700505#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_