blob: 5344e0fbde6157b2d1a36e096e658587c1a3bd8f [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) \
Alex Light8c2b9292017-11-09 13:21:01 -080083 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc) \
84 fn(DdmPublishChunk, ArtJvmtiEvent::kDdmPublishChunk)
Andreas Gampe983c1752017-01-23 19:46:56 -080085
86template <ArtJvmtiEvent kEvent>
87struct EventFnType {
88};
89
Alex Light8c2b9292017-11-09 13:21:01 -080090#define EVENT_FN_TYPE(name, enum_name) \
91template <> \
92struct EventFnType<enum_name> { \
93 using type = decltype(ArtJvmtiEventCallbacks().name); \
Andreas Gampe983c1752017-01-23 19:46:56 -080094};
95
96FORALL_EVENT_TYPES(EVENT_FN_TYPE)
97
98#undef EVENT_FN_TYPE
99
100template <ArtJvmtiEvent kEvent>
101ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
102
103#define GET_CALLBACK(name, enum_name) \
104template <> \
105ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
106 ArtJvmTiEnv* env) { \
107 if (env->event_callbacks == nullptr) { \
108 return nullptr; \
109 } \
110 return env->event_callbacks->name; \
Andreas Gampe77708d92016-10-07 11:48:21 -0700111}
112
Andreas Gampe983c1752017-01-23 19:46:56 -0800113FORALL_EVENT_TYPES(GET_CALLBACK)
Alex Light6ac57502017-01-19 15:05:06 -0800114
Andreas Gampe983c1752017-01-23 19:46:56 -0800115#undef GET_CALLBACK
116
117#undef FORALL_EVENT_TYPES
118
119} // namespace impl
120
121// C++ does not allow partial template function specialization. The dispatch for our separated
122// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Andreas Gampe983c1752017-01-23 19:46:56 -0800123template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800124inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800125 JNIEnv* jnienv,
126 jclass class_being_redefined,
127 jobject loader,
128 const char* name,
129 jobject protection_domain,
130 jint class_data_len,
131 const unsigned char* class_data,
132 jint* new_class_data_len,
133 unsigned char** new_class_data) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800134 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
135 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700136 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800137 jint current_len = class_data_len;
138 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
139 ArtJvmTiEnv* last_env = nullptr;
140 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700141 if (env == nullptr) {
142 continue;
143 }
Alex Light9df79b72017-09-12 08:57:31 -0700144 jint new_len = 0;
145 unsigned char* new_data = nullptr;
146 DispatchEventOnEnv<kEvent>(env,
147 thread,
148 jnienv,
149 class_being_redefined,
150 loader,
151 name,
152 protection_domain,
153 current_len,
154 static_cast<const unsigned char*>(current_class_data),
155 &new_len,
156 &new_data);
157 if (new_data != nullptr && new_data != current_class_data) {
158 // Destroy the data the last transformer made. We skip this if the previous state was the
159 // initial one since we don't know here which jvmtiEnv allocated it.
160 // NB Currently this doesn't matter since all allocations just go to malloc but in the
161 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
162 if (last_env != nullptr) {
163 last_env->Deallocate(current_class_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700164 }
Alex Light9df79b72017-09-12 08:57:31 -0700165 last_env = env;
166 current_class_data = new_data;
167 current_len = new_len;
Alex Light6ac57502017-01-19 15:05:06 -0800168 }
169 }
170 if (last_env != nullptr) {
171 *new_class_data_len = current_len;
172 *new_class_data = current_class_data;
173 }
174}
175
Andreas Gampe983c1752017-01-23 19:46:56 -0800176// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
177// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800178
Andreas Gampe983c1752017-01-23 19:46:56 -0800179template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700180inline void EventHandler::ExecuteCallback(ArtJvmTiEnv* env, Args... args) {
181 using FnType = typename impl::EventFnType<kEvent>::type;
182 FnType callback = impl::GetCallback<kEvent>(env);
183 if (callback != nullptr) {
184 (*callback)(env, args...);
185 }
186}
187
188template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700189inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Alex Light9df79b72017-09-12 08:57:31 -0700190 static_assert(!std::is_same<JNIEnv*,
191 typename std::decay_t<
192 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
193 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
194 DCHECK(thread == nullptr || !thread->IsExceptionPending());
Andreas Gampe77708d92016-10-07 11:48:21 -0700195 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700196 if (env != nullptr) {
Alex Light9df79b72017-09-12 08:57:31 -0700197 DispatchEventOnEnv<kEvent, Args...>(env, thread, args...);
Alex Lightbb766462017-04-12 16:13:33 -0700198 }
Andreas Gampea1705ea2017-03-28 20:12:13 -0700199 }
200}
201
Alex Light9df79b72017-09-12 08:57:31 -0700202// Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash
203// pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI
204// specification we allow exceptions originating from events to overwrite the current exception,
205// including exceptions originating from earlier events.
206class ScopedEventDispatchEnvironment FINAL : public art::ValueObject {
207 public:
208 explicit ScopedEventDispatchEnvironment(JNIEnv* env)
209 : env_(env),
210 thr_(env_, env_->ExceptionOccurred()),
211 suspend_(art::Thread::Current(), art::kNative) {
212 // The spec doesn't say how much local data should be there, so we just give 128 which seems
213 // likely to be enough for most cases.
214 env_->PushLocalFrame(128);
215 env_->ExceptionClear();
216 UNUSED(suspend_);
217 }
218
219 ~ScopedEventDispatchEnvironment() {
220 if (thr_.get() != nullptr && !env_->ExceptionCheck()) {
221 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
222 // of the newest exception.
223 env_->Throw(thr_.get());
224 }
225 env_->PopLocalFrame(nullptr);
226 }
227
228 private:
229 JNIEnv* env_;
230 ScopedLocalRef<jthrowable> thr_;
231 // Not actually unused. The destructor/constructor does important work.
232 art::ScopedThreadStateChange suspend_;
233
234 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
235};
236
Alex Lightb7edcda2017-04-27 13:20:31 -0700237template <ArtJvmtiEvent kEvent, typename ...Args>
238inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
239 for (ArtJvmTiEnv* env : envs) {
240 if (env != nullptr) {
Alex Light9df79b72017-09-12 08:57:31 -0700241 DispatchEventOnEnv<kEvent, Args...>(env, thread, jnienv, args...);
Alex Lightb7edcda2017-04-27 13:20:31 -0700242 }
243 }
244}
245
Andreas Gampea1705ea2017-03-28 20:12:13 -0700246template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700247inline void EventHandler::DispatchEventOnEnv(
248 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
249 DCHECK(env != nullptr);
250 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
251 ScopedEventDispatchEnvironment sede(jnienv);
252 ExecuteCallback<kEvent, JNIEnv*, Args...>(env, jnienv, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700253 }
254}
255
Alex Light9df79b72017-09-12 08:57:31 -0700256template <ArtJvmtiEvent kEvent, typename ...Args>
257inline void EventHandler::DispatchEventOnEnv(
258 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
259 static_assert(!std::is_same<JNIEnv*,
260 typename std::decay_t<
261 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
262 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
263 if (ShouldDispatch<kEvent>(env, thread, args...)) {
264 ExecuteCallback<kEvent, Args...>(env, args...);
265 }
266}
267
268// Events that need custom logic for if we send the event but are otherwise normal. This includes
269// the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
270
Alex Lighta26e3492017-06-27 17:55:37 -0700271// Need to give custom specializations for Breakpoint since it needs to filter out which particular
272// methods/dex_pcs agents get notified on.
273template <>
Alex Light9df79b72017-09-12 08:57:31 -0700274inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
275 ArtJvmTiEnv* env,
276 art::Thread* thread,
277 JNIEnv* jnienv ATTRIBUTE_UNUSED,
278 jthread jni_thread ATTRIBUTE_UNUSED,
279 jmethodID jmethod,
280 jlocation location) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700281 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Lighta26e3492017-06-27 17:55:37 -0700282 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
Alex Light9df79b72017-09-12 08:57:31 -0700283 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
284 env->breakpoints.find({method, location}) != env->breakpoints.end();
Alex Lighta26e3492017-06-27 17:55:37 -0700285}
286
Alex Lighte814f9d2017-07-31 16:14:39 -0700287template <>
Alex Light9df79b72017-09-12 08:57:31 -0700288inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
289 ArtJvmTiEnv* env,
Alex Lighte814f9d2017-07-31 16:14:39 -0700290 art::Thread* thread,
Alex Light9df79b72017-09-12 08:57:31 -0700291 JNIEnv* jnienv ATTRIBUTE_UNUSED,
292 jthread jni_thread ATTRIBUTE_UNUSED,
293 jmethodID jmethod ATTRIBUTE_UNUSED,
294 jboolean is_exception ATTRIBUTE_UNUSED,
Alex Lighte814f9d2017-07-31 16:14:39 -0700295 const art::ShadowFrame* frame) const {
Alex Light9df79b72017-09-12 08:57:31 -0700296 // Search for the frame. Do this before checking if we need to send the event so that we don't
297 // have to deal with use-after-free or the frames being reallocated later.
Alex Lightb6106d52017-10-18 15:02:15 -0700298 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700299 return env->notify_frames.erase(frame) != 0 &&
300 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
Alex Lighte814f9d2017-07-31 16:14:39 -0700301}
302
Alex Light084fa372017-06-16 08:58:34 -0700303// Need to give custom specializations for FieldAccess and FieldModification since they need to
304// filter out which particular fields agents want to get notified on.
305// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
306// could make the system more performant.
307template <>
Alex Light9df79b72017-09-12 08:57:31 -0700308inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
309 ArtJvmTiEnv* env,
310 art::Thread* thread,
311 JNIEnv* jnienv ATTRIBUTE_UNUSED,
312 jthread jni_thread ATTRIBUTE_UNUSED,
313 jmethodID method ATTRIBUTE_UNUSED,
314 jlocation location ATTRIBUTE_UNUSED,
315 jclass field_klass ATTRIBUTE_UNUSED,
316 jobject object ATTRIBUTE_UNUSED,
317 jfieldID field,
318 char type_char ATTRIBUTE_UNUSED,
319 jvalue val ATTRIBUTE_UNUSED) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700320 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700321 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
322 env->modify_watched_fields.find(
323 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
Alex Light084fa372017-06-16 08:58:34 -0700324}
325
326template <>
Alex Light9df79b72017-09-12 08:57:31 -0700327inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
328 ArtJvmTiEnv* env,
329 art::Thread* thread,
330 JNIEnv* jnienv ATTRIBUTE_UNUSED,
331 jthread jni_thread ATTRIBUTE_UNUSED,
332 jmethodID method ATTRIBUTE_UNUSED,
333 jlocation location ATTRIBUTE_UNUSED,
334 jclass field_klass ATTRIBUTE_UNUSED,
335 jobject object ATTRIBUTE_UNUSED,
336 jfieldID field) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700337 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700338 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
339 env->access_watched_fields.find(
340 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
341}
342
343// Need to give custom specializations for FramePop since it needs to filter out which particular
344// agents get the event. This specialization gets an extra argument so we can determine which (if
345// any) environments have the frame pop.
346// TODO It might be useful to use more template magic to have this only define ShouldDispatch or
347// something.
348template <>
349inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
350 ArtJvmTiEnv* env,
351 JNIEnv* jnienv,
352 jthread jni_thread,
353 jmethodID jmethod,
354 jboolean is_exception,
355 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
356 ExecuteCallback<ArtJvmtiEvent::kFramePop>(
357 env, jnienv, jni_thread, jmethod, is_exception);
Alex Light084fa372017-06-16 08:58:34 -0700358}
359
Alex Lightd78ddec2017-04-18 15:20:38 -0700360// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
361// variable.
362template <>
363inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
364 JNIEnv* jnienv,
365 jthread jni_thread,
366 jmethodID method,
367 void* cur_method,
368 void** new_method) const {
369 *new_method = cur_method;
370 for (ArtJvmTiEnv* env : envs) {
Alex Light9df79b72017-09-12 08:57:31 -0700371 if (env != nullptr) {
372 *new_method = cur_method;
373 DispatchEventOnEnv<ArtJvmtiEvent::kNativeMethodBind>(env,
374 thread,
375 jnienv,
376 jni_thread,
377 method,
378 cur_method,
379 new_method);
Alex Lightd78ddec2017-04-18 15:20:38 -0700380 if (*new_method != nullptr) {
381 cur_method = *new_method;
382 }
383 }
384 }
Alex Light9df79b72017-09-12 08:57:31 -0700385 *new_method = cur_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700386}
387
Andreas Gampe983c1752017-01-23 19:46:56 -0800388// C++ does not allow partial template function specialization. The dispatch for our separated
389// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
390// The following two DispatchEvent specializations dispatch to it.
391template <>
392inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
393 art::Thread* thread,
394 JNIEnv* jnienv,
395 jclass class_being_redefined,
396 jobject loader,
397 const char* name,
398 jobject protection_domain,
399 jint class_data_len,
400 const unsigned char* class_data,
401 jint* new_class_data_len,
402 unsigned char** new_class_data) const {
403 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
404 thread,
405 jnienv,
406 class_being_redefined,
407 loader,
408 name,
409 protection_domain,
410 class_data_len,
411 class_data,
412 new_class_data_len,
413 new_class_data);
414}
Alex Light9df79b72017-09-12 08:57:31 -0700415
Andreas Gampe983c1752017-01-23 19:46:56 -0800416template <>
417inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
418 art::Thread* thread,
419 JNIEnv* jnienv,
420 jclass class_being_redefined,
421 jobject loader,
422 const char* name,
423 jobject protection_domain,
424 jint class_data_len,
425 const unsigned char* class_data,
426 jint* new_class_data_len,
427 unsigned char** new_class_data) const {
428 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
429 thread,
430 jnienv,
431 class_being_redefined,
432 loader,
433 name,
434 protection_domain,
435 class_data_len,
436 class_data,
437 new_class_data_len,
438 new_class_data);
439}
Alex Light40d87f42017-01-18 10:27:06 -0800440
Andreas Gampe983c1752017-01-23 19:46:56 -0800441template <ArtJvmtiEvent kEvent>
Alex Light9df79b72017-09-12 08:57:31 -0700442inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) {
Andreas Gampe983c1752017-01-23 19:46:56 -0800443 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
444
445 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800446 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800447 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800448 }
449 return dispatch;
450}
451
Alex Light9df79b72017-09-12 08:57:31 -0700452template <ArtJvmtiEvent kEvent, typename ...Args>
453inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
454 art::Thread* thread,
455 Args... args ATTRIBUTE_UNUSED) const {
456 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
457 void(*)(jvmtiEnv*, Args...)>::value,
458 "Unexpected different type of shouldDispatch");
459
460 return ShouldDispatchOnThread<kEvent>(env, thread);
461}
462
Alex Light73afd322017-01-18 11:17:47 -0800463inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
464 bool union_value = false;
465 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700466 if (stored_env == nullptr) {
467 continue;
468 }
Alex Light73afd322017-01-18 11:17:47 -0800469 union_value |= stored_env->event_masks.global_event_mask.Test(event);
470 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
471 if (union_value) {
472 break;
473 }
474 }
475 global_mask.Set(event, union_value);
476}
477
478inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
479 const jvmtiCapabilities& caps,
480 bool added) {
481 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
482 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700483 return (added && caps.can_access_local_variables == 1) ||
Alex Light0fa17862017-10-24 13:43:05 -0700484 caps.can_generate_breakpoint_events == 1 ||
Alex Lightbebd7bd2017-07-25 14:05:52 -0700485 (caps.can_retransform_classes == 1 &&
486 IsEventEnabledAnywhere(event) &&
487 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800488}
489
490inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
491 const jvmtiCapabilities& caps,
492 bool added) {
493 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
494 env->event_masks.HandleChangedCapabilities(caps, added);
495 if (caps.can_retransform_classes == 1) {
496 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
497 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
498 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700499 if (added && caps.can_access_local_variables == 1) {
500 HandleLocalAccessCapabilityAdded();
501 }
Alex Light0fa17862017-10-24 13:43:05 -0700502 if (caps.can_generate_breakpoint_events == 1) {
503 HandleBreakpointEventsChanged(added);
504 }
Alex Light73afd322017-01-18 11:17:47 -0800505 }
506}
507
Andreas Gampe77708d92016-10-07 11:48:21 -0700508} // namespace openjdkjvmti
509
Andreas Gampe06c42a52017-07-26 14:17:14 -0700510#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_