blob: ab8e6def2d41d41ba7898ec364992364e130af28 [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
Andreas Gampe77708d92016-10-07 11:48:21 -070024#include "events.h"
Alex Light084fa372017-06-16 08:58:34 -070025#include "jni_internal.h"
Steven Morelande431e272017-07-18 16:53:49 -070026#include "nativehelper/ScopedLocalRef.h"
Alex Light9df79b72017-09-12 08:57:31 -070027#include "scoped_thread_state_change-inl.h"
Alex Lighta26e3492017-06-27 17:55:37 -070028#include "ti_breakpoint.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070029
30#include "art_jvmti.h"
31
32namespace openjdkjvmti {
33
Alex Light73afd322017-01-18 11:17:47 -080034static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
35 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
36 if (env->capabilities.can_retransform_classes) {
37 return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
38 } else {
39 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
40 }
41 } else {
42 return static_cast<ArtJvmtiEvent>(e);
43 }
Alex Light40d87f42017-01-18 10:27:06 -080044}
45
Andreas Gampe983c1752017-01-23 19:46:56 -080046namespace impl {
Andreas Gampe77708d92016-10-07 11:48:21 -070047
Andreas Gampe983c1752017-01-23 19:46:56 -080048// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070049
Andreas Gampe983c1752017-01-23 19:46:56 -080050#define FORALL_EVENT_TYPES(fn) \
51 fn(VMInit, ArtJvmtiEvent::kVmInit) \
52 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
53 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
54 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
55 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
56 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
57 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
58 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
59 fn(VMStart, ArtJvmtiEvent::kVmStart) \
60 fn(Exception, ArtJvmtiEvent::kException) \
61 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
62 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
63 fn(FramePop, ArtJvmtiEvent::kFramePop) \
64 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
65 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
66 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
67 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
68 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
69 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
70 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
71 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
72 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
73 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
74 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
75 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
76 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
77 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
78 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
79 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
80 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
81 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
82 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc)
83
84template <ArtJvmtiEvent kEvent>
85struct EventFnType {
86};
87
88#define EVENT_FN_TYPE(name, enum_name) \
89template <> \
90struct EventFnType<enum_name> { \
91 using type = decltype(jvmtiEventCallbacks().name); \
92};
93
94FORALL_EVENT_TYPES(EVENT_FN_TYPE)
95
96#undef EVENT_FN_TYPE
97
98template <ArtJvmtiEvent kEvent>
99ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
100
101#define GET_CALLBACK(name, enum_name) \
102template <> \
103ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
104 ArtJvmTiEnv* env) { \
105 if (env->event_callbacks == nullptr) { \
106 return nullptr; \
107 } \
108 return env->event_callbacks->name; \
Andreas Gampe77708d92016-10-07 11:48:21 -0700109}
110
Andreas Gampe983c1752017-01-23 19:46:56 -0800111FORALL_EVENT_TYPES(GET_CALLBACK)
Alex Light6ac57502017-01-19 15:05:06 -0800112
Andreas Gampe983c1752017-01-23 19:46:56 -0800113#undef GET_CALLBACK
114
115#undef FORALL_EVENT_TYPES
116
117} // namespace impl
118
119// C++ does not allow partial template function specialization. The dispatch for our separated
120// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Andreas Gampe983c1752017-01-23 19:46:56 -0800121template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800122inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800123 JNIEnv* jnienv,
124 jclass class_being_redefined,
125 jobject loader,
126 const char* name,
127 jobject protection_domain,
128 jint class_data_len,
129 const unsigned char* class_data,
130 jint* new_class_data_len,
131 unsigned char** new_class_data) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800132 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
133 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700134 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800135 jint current_len = class_data_len;
136 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
137 ArtJvmTiEnv* last_env = nullptr;
138 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700139 if (env == nullptr) {
140 continue;
141 }
Alex Light9df79b72017-09-12 08:57:31 -0700142 jint new_len = 0;
143 unsigned char* new_data = nullptr;
144 DispatchEventOnEnv<kEvent>(env,
145 thread,
146 jnienv,
147 class_being_redefined,
148 loader,
149 name,
150 protection_domain,
151 current_len,
152 static_cast<const unsigned char*>(current_class_data),
153 &new_len,
154 &new_data);
155 if (new_data != nullptr && new_data != current_class_data) {
156 // Destroy the data the last transformer made. We skip this if the previous state was the
157 // initial one since we don't know here which jvmtiEnv allocated it.
158 // NB Currently this doesn't matter since all allocations just go to malloc but in the
159 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
160 if (last_env != nullptr) {
161 last_env->Deallocate(current_class_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700162 }
Alex Light9df79b72017-09-12 08:57:31 -0700163 last_env = env;
164 current_class_data = new_data;
165 current_len = new_len;
Alex Light6ac57502017-01-19 15:05:06 -0800166 }
167 }
168 if (last_env != nullptr) {
169 *new_class_data_len = current_len;
170 *new_class_data = current_class_data;
171 }
172}
173
Andreas Gampe983c1752017-01-23 19:46:56 -0800174// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
175// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800176
Andreas Gampe983c1752017-01-23 19:46:56 -0800177template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700178inline void EventHandler::ExecuteCallback(ArtJvmTiEnv* env, Args... args) {
179 using FnType = typename impl::EventFnType<kEvent>::type;
180 FnType callback = impl::GetCallback<kEvent>(env);
181 if (callback != nullptr) {
182 (*callback)(env, args...);
183 }
184}
185
186template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700187inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Alex Light9df79b72017-09-12 08:57:31 -0700188 static_assert(!std::is_same<JNIEnv*,
189 typename std::decay_t<
190 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
191 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
192 DCHECK(thread == nullptr || !thread->IsExceptionPending());
Andreas Gampe77708d92016-10-07 11:48:21 -0700193 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700194 if (env != nullptr) {
Alex Light9df79b72017-09-12 08:57:31 -0700195 DispatchEventOnEnv<kEvent, Args...>(env, thread, args...);
Alex Lightbb766462017-04-12 16:13:33 -0700196 }
Andreas Gampea1705ea2017-03-28 20:12:13 -0700197 }
198}
199
Alex Light9df79b72017-09-12 08:57:31 -0700200// Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash
201// pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI
202// specification we allow exceptions originating from events to overwrite the current exception,
203// including exceptions originating from earlier events.
204class ScopedEventDispatchEnvironment FINAL : public art::ValueObject {
205 public:
206 explicit ScopedEventDispatchEnvironment(JNIEnv* env)
207 : env_(env),
208 thr_(env_, env_->ExceptionOccurred()),
209 suspend_(art::Thread::Current(), art::kNative) {
210 // The spec doesn't say how much local data should be there, so we just give 128 which seems
211 // likely to be enough for most cases.
212 env_->PushLocalFrame(128);
213 env_->ExceptionClear();
214 UNUSED(suspend_);
215 }
216
217 ~ScopedEventDispatchEnvironment() {
218 if (thr_.get() != nullptr && !env_->ExceptionCheck()) {
219 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
220 // of the newest exception.
221 env_->Throw(thr_.get());
222 }
223 env_->PopLocalFrame(nullptr);
224 }
225
226 private:
227 JNIEnv* env_;
228 ScopedLocalRef<jthrowable> thr_;
229 // Not actually unused. The destructor/constructor does important work.
230 art::ScopedThreadStateChange suspend_;
231
232 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
233};
234
Alex Lightb7edcda2017-04-27 13:20:31 -0700235template <ArtJvmtiEvent kEvent, typename ...Args>
236inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
237 for (ArtJvmTiEnv* env : envs) {
238 if (env != nullptr) {
Alex Light9df79b72017-09-12 08:57:31 -0700239 DispatchEventOnEnv<kEvent, Args...>(env, thread, jnienv, args...);
Alex Lightb7edcda2017-04-27 13:20:31 -0700240 }
241 }
242}
243
Andreas Gampea1705ea2017-03-28 20:12:13 -0700244template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700245inline void EventHandler::DispatchEventOnEnv(
246 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
247 DCHECK(env != nullptr);
248 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
249 ScopedEventDispatchEnvironment sede(jnienv);
250 ExecuteCallback<kEvent, JNIEnv*, Args...>(env, jnienv, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700251 }
252}
253
Alex Light9df79b72017-09-12 08:57:31 -0700254template <ArtJvmtiEvent kEvent, typename ...Args>
255inline void EventHandler::DispatchEventOnEnv(
256 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
257 static_assert(!std::is_same<JNIEnv*,
258 typename std::decay_t<
259 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
260 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
261 if (ShouldDispatch<kEvent>(env, thread, args...)) {
262 ExecuteCallback<kEvent, Args...>(env, args...);
263 }
264}
265
266// Events that need custom logic for if we send the event but are otherwise normal. This includes
267// the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
268
Alex Lighta26e3492017-06-27 17:55:37 -0700269// Need to give custom specializations for Breakpoint since it needs to filter out which particular
270// methods/dex_pcs agents get notified on.
271template <>
Alex Light9df79b72017-09-12 08:57:31 -0700272inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
273 ArtJvmTiEnv* env,
274 art::Thread* thread,
275 JNIEnv* jnienv ATTRIBUTE_UNUSED,
276 jthread jni_thread ATTRIBUTE_UNUSED,
277 jmethodID jmethod,
278 jlocation location) const {
Alex Lighta26e3492017-06-27 17:55:37 -0700279 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
Alex Light9df79b72017-09-12 08:57:31 -0700280 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
281 env->breakpoints.find({method, location}) != env->breakpoints.end();
Alex Lighta26e3492017-06-27 17:55:37 -0700282}
283
Alex Lighte814f9d2017-07-31 16:14:39 -0700284template <>
Alex Light9df79b72017-09-12 08:57:31 -0700285inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
286 ArtJvmTiEnv* env,
Alex Lighte814f9d2017-07-31 16:14:39 -0700287 art::Thread* thread,
Alex Light9df79b72017-09-12 08:57:31 -0700288 JNIEnv* jnienv ATTRIBUTE_UNUSED,
289 jthread jni_thread ATTRIBUTE_UNUSED,
290 jmethodID jmethod ATTRIBUTE_UNUSED,
291 jboolean is_exception ATTRIBUTE_UNUSED,
Alex Lighte814f9d2017-07-31 16:14:39 -0700292 const art::ShadowFrame* frame) const {
Alex Light9df79b72017-09-12 08:57:31 -0700293 // Search for the frame. Do this before checking if we need to send the event so that we don't
294 // have to deal with use-after-free or the frames being reallocated later.
295 return env->notify_frames.erase(frame) != 0 &&
296 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
Alex Lighte814f9d2017-07-31 16:14:39 -0700297}
298
Alex Light084fa372017-06-16 08:58:34 -0700299// Need to give custom specializations for FieldAccess and FieldModification since they need to
300// filter out which particular fields agents want to get notified on.
301// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
302// could make the system more performant.
303template <>
Alex Light9df79b72017-09-12 08:57:31 -0700304inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
305 ArtJvmTiEnv* env,
306 art::Thread* thread,
307 JNIEnv* jnienv ATTRIBUTE_UNUSED,
308 jthread jni_thread ATTRIBUTE_UNUSED,
309 jmethodID method ATTRIBUTE_UNUSED,
310 jlocation location ATTRIBUTE_UNUSED,
311 jclass field_klass ATTRIBUTE_UNUSED,
312 jobject object ATTRIBUTE_UNUSED,
313 jfieldID field,
314 char type_char ATTRIBUTE_UNUSED,
315 jvalue val ATTRIBUTE_UNUSED) const {
316 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
317 env->modify_watched_fields.find(
318 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
Alex Light084fa372017-06-16 08:58:34 -0700319}
320
321template <>
Alex Light9df79b72017-09-12 08:57:31 -0700322inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
323 ArtJvmTiEnv* env,
324 art::Thread* thread,
325 JNIEnv* jnienv ATTRIBUTE_UNUSED,
326 jthread jni_thread ATTRIBUTE_UNUSED,
327 jmethodID method ATTRIBUTE_UNUSED,
328 jlocation location ATTRIBUTE_UNUSED,
329 jclass field_klass ATTRIBUTE_UNUSED,
330 jobject object ATTRIBUTE_UNUSED,
331 jfieldID field) const {
332 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
333 env->access_watched_fields.find(
334 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
335}
336
337// Need to give custom specializations for FramePop since it needs to filter out which particular
338// agents get the event. This specialization gets an extra argument so we can determine which (if
339// any) environments have the frame pop.
340// TODO It might be useful to use more template magic to have this only define ShouldDispatch or
341// something.
342template <>
343inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
344 ArtJvmTiEnv* env,
345 JNIEnv* jnienv,
346 jthread jni_thread,
347 jmethodID jmethod,
348 jboolean is_exception,
349 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
350 ExecuteCallback<ArtJvmtiEvent::kFramePop>(
351 env, jnienv, jni_thread, jmethod, is_exception);
Alex Light084fa372017-06-16 08:58:34 -0700352}
353
Alex Lightd78ddec2017-04-18 15:20:38 -0700354// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
355// variable.
356template <>
357inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
358 JNIEnv* jnienv,
359 jthread jni_thread,
360 jmethodID method,
361 void* cur_method,
362 void** new_method) const {
363 *new_method = cur_method;
364 for (ArtJvmTiEnv* env : envs) {
Alex Light9df79b72017-09-12 08:57:31 -0700365 if (env != nullptr) {
366 *new_method = cur_method;
367 DispatchEventOnEnv<ArtJvmtiEvent::kNativeMethodBind>(env,
368 thread,
369 jnienv,
370 jni_thread,
371 method,
372 cur_method,
373 new_method);
Alex Lightd78ddec2017-04-18 15:20:38 -0700374 if (*new_method != nullptr) {
375 cur_method = *new_method;
376 }
377 }
378 }
Alex Light9df79b72017-09-12 08:57:31 -0700379 *new_method = cur_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700380}
381
Andreas Gampe983c1752017-01-23 19:46:56 -0800382// C++ does not allow partial template function specialization. The dispatch for our separated
383// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
384// The following two DispatchEvent specializations dispatch to it.
385template <>
386inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
387 art::Thread* thread,
388 JNIEnv* jnienv,
389 jclass class_being_redefined,
390 jobject loader,
391 const char* name,
392 jobject protection_domain,
393 jint class_data_len,
394 const unsigned char* class_data,
395 jint* new_class_data_len,
396 unsigned char** new_class_data) const {
397 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
398 thread,
399 jnienv,
400 class_being_redefined,
401 loader,
402 name,
403 protection_domain,
404 class_data_len,
405 class_data,
406 new_class_data_len,
407 new_class_data);
408}
Alex Light9df79b72017-09-12 08:57:31 -0700409
Andreas Gampe983c1752017-01-23 19:46:56 -0800410template <>
411inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
412 art::Thread* thread,
413 JNIEnv* jnienv,
414 jclass class_being_redefined,
415 jobject loader,
416 const char* name,
417 jobject protection_domain,
418 jint class_data_len,
419 const unsigned char* class_data,
420 jint* new_class_data_len,
421 unsigned char** new_class_data) const {
422 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
423 thread,
424 jnienv,
425 class_being_redefined,
426 loader,
427 name,
428 protection_domain,
429 class_data_len,
430 class_data,
431 new_class_data_len,
432 new_class_data);
433}
Alex Light40d87f42017-01-18 10:27:06 -0800434
Andreas Gampe983c1752017-01-23 19:46:56 -0800435template <ArtJvmtiEvent kEvent>
Alex Light9df79b72017-09-12 08:57:31 -0700436inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) {
Andreas Gampe983c1752017-01-23 19:46:56 -0800437 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
438
439 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800440 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800441 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800442 }
443 return dispatch;
444}
445
Alex Light9df79b72017-09-12 08:57:31 -0700446template <ArtJvmtiEvent kEvent, typename ...Args>
447inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
448 art::Thread* thread,
449 Args... args ATTRIBUTE_UNUSED) const {
450 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
451 void(*)(jvmtiEnv*, Args...)>::value,
452 "Unexpected different type of shouldDispatch");
453
454 return ShouldDispatchOnThread<kEvent>(env, thread);
455}
456
Alex Light73afd322017-01-18 11:17:47 -0800457inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
458 bool union_value = false;
459 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700460 if (stored_env == nullptr) {
461 continue;
462 }
Alex Light73afd322017-01-18 11:17:47 -0800463 union_value |= stored_env->event_masks.global_event_mask.Test(event);
464 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
465 if (union_value) {
466 break;
467 }
468 }
469 global_mask.Set(event, union_value);
470}
471
472inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
473 const jvmtiCapabilities& caps,
474 bool added) {
475 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
476 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700477 return (added && caps.can_access_local_variables == 1) ||
478 (caps.can_retransform_classes == 1 &&
479 IsEventEnabledAnywhere(event) &&
480 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800481}
482
483inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
484 const jvmtiCapabilities& caps,
485 bool added) {
486 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
487 env->event_masks.HandleChangedCapabilities(caps, added);
488 if (caps.can_retransform_classes == 1) {
489 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
490 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
491 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700492 if (added && caps.can_access_local_variables == 1) {
493 HandleLocalAccessCapabilityAdded();
494 }
Alex Light73afd322017-01-18 11:17:47 -0800495 }
496}
497
Andreas Gampe77708d92016-10-07 11:48:21 -0700498} // namespace openjdkjvmti
499
Andreas Gampe06c42a52017-07-26 14:17:14 -0700500#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_