blob: 31edc73ac6341f6c032bfbac17e742e6f999b386 [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>
21
Andreas Gampe77708d92016-10-07 11:48:21 -070022#include "events.h"
Alex Light084fa372017-06-16 08:58:34 -070023#include "jni_internal.h"
Steven Morelande431e272017-07-18 16:53:49 -070024#include "nativehelper/ScopedLocalRef.h"
Alex Lighta26e3492017-06-27 17:55:37 -070025#include "ti_breakpoint.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070026
27#include "art_jvmti.h"
28
29namespace openjdkjvmti {
30
Alex Light73afd322017-01-18 11:17:47 -080031static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
32 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
33 if (env->capabilities.can_retransform_classes) {
34 return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
35 } else {
36 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
37 }
38 } else {
39 return static_cast<ArtJvmtiEvent>(e);
40 }
Alex Light40d87f42017-01-18 10:27:06 -080041}
42
Andreas Gampe983c1752017-01-23 19:46:56 -080043namespace impl {
Andreas Gampe77708d92016-10-07 11:48:21 -070044
Andreas Gampe983c1752017-01-23 19:46:56 -080045// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070046
Andreas Gampe983c1752017-01-23 19:46:56 -080047#define FORALL_EVENT_TYPES(fn) \
48 fn(VMInit, ArtJvmtiEvent::kVmInit) \
49 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
50 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
51 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
52 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
53 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
54 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
55 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
56 fn(VMStart, ArtJvmtiEvent::kVmStart) \
57 fn(Exception, ArtJvmtiEvent::kException) \
58 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
59 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
60 fn(FramePop, ArtJvmtiEvent::kFramePop) \
61 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
62 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
63 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
64 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
65 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
66 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
67 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
68 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
69 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
70 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
71 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
72 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
73 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
74 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
75 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
76 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
77 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
78 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
79 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc)
80
81template <ArtJvmtiEvent kEvent>
82struct EventFnType {
83};
84
85#define EVENT_FN_TYPE(name, enum_name) \
86template <> \
87struct EventFnType<enum_name> { \
88 using type = decltype(jvmtiEventCallbacks().name); \
89};
90
91FORALL_EVENT_TYPES(EVENT_FN_TYPE)
92
93#undef EVENT_FN_TYPE
94
95template <ArtJvmtiEvent kEvent>
96ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
97
98#define GET_CALLBACK(name, enum_name) \
99template <> \
100ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
101 ArtJvmTiEnv* env) { \
102 if (env->event_callbacks == nullptr) { \
103 return nullptr; \
104 } \
105 return env->event_callbacks->name; \
Andreas Gampe77708d92016-10-07 11:48:21 -0700106}
107
Andreas Gampe983c1752017-01-23 19:46:56 -0800108FORALL_EVENT_TYPES(GET_CALLBACK)
Alex Light6ac57502017-01-19 15:05:06 -0800109
Andreas Gampe983c1752017-01-23 19:46:56 -0800110#undef GET_CALLBACK
111
112#undef FORALL_EVENT_TYPES
113
114} // namespace impl
115
116// C++ does not allow partial template function specialization. The dispatch for our separated
117// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Alex Light6ac57502017-01-19 15:05:06 -0800118// TODO Locking of some type!
Andreas Gampe983c1752017-01-23 19:46:56 -0800119template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800120inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800121 JNIEnv* jnienv,
122 jclass class_being_redefined,
123 jobject loader,
124 const char* name,
125 jobject protection_domain,
126 jint class_data_len,
127 const unsigned char* class_data,
128 jint* new_class_data_len,
129 unsigned char** new_class_data) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800130 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
131 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700132 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800133 jint current_len = class_data_len;
134 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
135 ArtJvmTiEnv* last_env = nullptr;
136 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700137 if (env == nullptr) {
138 continue;
139 }
Andreas Gampe983c1752017-01-23 19:46:56 -0800140 if (ShouldDispatch<kEvent>(env, thread)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700141 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
142 jnienv->ExceptionClear();
Alex Light440b5d92017-01-24 15:32:25 -0800143 jint new_len = 0;
144 unsigned char* new_data = nullptr;
Andreas Gampe983c1752017-01-23 19:46:56 -0800145 auto callback = impl::GetCallback<kEvent>(env);
Alex Light6ac57502017-01-19 15:05:06 -0800146 callback(env,
147 jnienv,
148 class_being_redefined,
149 loader,
150 name,
151 protection_domain,
152 current_len,
153 current_class_data,
154 &new_len,
155 &new_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700156 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
157 jnienv->Throw(thr.get());
158 }
Alex Light6ac57502017-01-19 15:05:06 -0800159 if (new_data != nullptr && new_data != current_class_data) {
160 // Destroy the data the last transformer made. We skip this if the previous state was the
161 // initial one since we don't know here which jvmtiEnv allocated it.
162 // NB Currently this doesn't matter since all allocations just go to malloc but in the
163 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
164 if (last_env != nullptr) {
165 last_env->Deallocate(current_class_data);
166 }
167 last_env = env;
168 current_class_data = new_data;
169 current_len = new_len;
170 }
171 }
172 }
173 if (last_env != nullptr) {
174 *new_class_data_len = current_len;
175 *new_class_data = current_class_data;
176 }
177}
178
Andreas Gampe983c1752017-01-23 19:46:56 -0800179// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
180// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800181
Andreas Gampe983c1752017-01-23 19:46:56 -0800182template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700183inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Andreas Gampe77708d92016-10-07 11:48:21 -0700184 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700185 if (env != nullptr) {
186 DispatchEvent<kEvent, Args...>(env, thread, args...);
187 }
Andreas Gampea1705ea2017-03-28 20:12:13 -0700188 }
189}
190
Alex Lightb7edcda2017-04-27 13:20:31 -0700191// Events with JNIEnvs need to stash pending exceptions since they can cause new ones to be thrown.
192// In accordance with the JVMTI specification we allow exceptions originating from events to
193// overwrite the current exception, including exceptions originating from earlier events.
194// TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list of the
195// newest exception.
196template <ArtJvmtiEvent kEvent, typename ...Args>
197inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
198 for (ArtJvmTiEnv* env : envs) {
199 if (env != nullptr) {
200 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
201 jnienv->ExceptionClear();
202 DispatchEvent<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...);
203 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
204 jnienv->Throw(thr.get());
205 }
206 }
207 }
208}
209
Andreas Gampea1705ea2017-03-28 20:12:13 -0700210template <ArtJvmtiEvent kEvent, typename ...Args>
211inline void EventHandler::DispatchEvent(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
212 using FnType = void(jvmtiEnv*, Args...);
213 if (ShouldDispatch<kEvent>(env, thread)) {
214 FnType* callback = impl::GetCallback<kEvent>(env);
215 if (callback != nullptr) {
216 (*callback)(env, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700217 }
218 }
219}
220
Alex Lighta26e3492017-06-27 17:55:37 -0700221// Need to give custom specializations for Breakpoint since it needs to filter out which particular
222// methods/dex_pcs agents get notified on.
223template <>
224inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kBreakpoint>(art::Thread* thread,
225 JNIEnv* jnienv,
226 jthread jni_thread,
227 jmethodID jmethod,
228 jlocation location) const {
229 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
230 for (ArtJvmTiEnv* env : envs) {
231 // Search for a breakpoint on this particular method and location.
232 if (env != nullptr &&
233 ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
234 env->breakpoints.find({method, location}) != env->breakpoints.end()) {
235 // We temporarily clear any pending exceptions so the event can call back into java code.
236 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
237 jnienv->ExceptionClear();
238 auto callback = impl::GetCallback<ArtJvmtiEvent::kBreakpoint>(env);
239 (*callback)(env, jnienv, jni_thread, jmethod, location);
240 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
241 jnienv->Throw(thr.get());
242 }
243 }
244 }
245}
246
Alex Lighte814f9d2017-07-31 16:14:39 -0700247// Need to give custom specializations for FramePop since it needs to filter out which particular
248// agents get the event. This specialization gets an extra argument so we can determine which (if
249// any) environments have the frame pop.
250template <>
251inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFramePop>(
252 art::Thread* thread,
253 JNIEnv* jnienv,
254 jthread jni_thread,
255 jmethodID jmethod,
256 jboolean is_exception,
257 const art::ShadowFrame* frame) const {
258 for (ArtJvmTiEnv* env : envs) {
259 // Search for the frame. Do this before checking if we need to send the event so that we don't
260 // have to deal with use-after-free or the frames being reallocated later.
261 if (env != nullptr && env->notify_frames.erase(frame) != 0) {
262 if (ShouldDispatch<ArtJvmtiEvent::kFramePop>(env, thread)) {
263 // We temporarily clear any pending exceptions so the event can call back into java code.
264 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
265 jnienv->ExceptionClear();
266 auto callback = impl::GetCallback<ArtJvmtiEvent::kFramePop>(env);
267 (*callback)(env, jnienv, jni_thread, jmethod, is_exception);
268 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
269 jnienv->Throw(thr.get());
270 }
271 }
272 }
273 }
274}
275
Alex Light084fa372017-06-16 08:58:34 -0700276// Need to give custom specializations for FieldAccess and FieldModification since they need to
277// filter out which particular fields agents want to get notified on.
278// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
279// could make the system more performant.
280template <>
281inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFieldModification>(art::Thread* thread,
282 JNIEnv* jnienv,
283 jthread jni_thread,
284 jmethodID method,
285 jlocation location,
286 jclass field_klass,
287 jobject object,
288 jfieldID field,
289 char type_char,
290 jvalue val) const {
291 for (ArtJvmTiEnv* env : envs) {
292 if (env != nullptr &&
293 ShouldDispatch<ArtJvmtiEvent::kFieldModification>(env, thread) &&
294 env->modify_watched_fields.find(
295 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end()) {
296 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
297 jnienv->ExceptionClear();
298 auto callback = impl::GetCallback<ArtJvmtiEvent::kFieldModification>(env);
299 (*callback)(env,
300 jnienv,
301 jni_thread,
302 method,
303 location,
304 field_klass,
305 object,
306 field,
307 type_char,
308 val);
309 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
310 jnienv->Throw(thr.get());
311 }
312 }
313 }
314}
315
316template <>
317inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFieldAccess>(art::Thread* thread,
318 JNIEnv* jnienv,
319 jthread jni_thread,
320 jmethodID method,
321 jlocation location,
322 jclass field_klass,
323 jobject object,
324 jfieldID field) const {
325 for (ArtJvmTiEnv* env : envs) {
326 if (env != nullptr &&
327 ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
328 env->access_watched_fields.find(
329 art::jni::DecodeArtField(field)) != env->access_watched_fields.end()) {
330 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
331 jnienv->ExceptionClear();
332 auto callback = impl::GetCallback<ArtJvmtiEvent::kFieldAccess>(env);
333 (*callback)(env, jnienv, jni_thread, method, location, field_klass, object, field);
334 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
335 jnienv->Throw(thr.get());
336 }
337 }
338 }
339}
340
Alex Lightd78ddec2017-04-18 15:20:38 -0700341// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
342// variable.
343template <>
344inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
345 JNIEnv* jnienv,
346 jthread jni_thread,
347 jmethodID method,
348 void* cur_method,
349 void** new_method) const {
350 *new_method = cur_method;
351 for (ArtJvmTiEnv* env : envs) {
352 if (env != nullptr && ShouldDispatch<ArtJvmtiEvent::kNativeMethodBind>(env, thread)) {
353 auto callback = impl::GetCallback<ArtJvmtiEvent::kNativeMethodBind>(env);
354 (*callback)(env, jnienv, jni_thread, method, cur_method, new_method);
355 if (*new_method != nullptr) {
356 cur_method = *new_method;
357 }
358 }
359 }
360}
361
Andreas Gampe983c1752017-01-23 19:46:56 -0800362// C++ does not allow partial template function specialization. The dispatch for our separated
363// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
364// The following two DispatchEvent specializations dispatch to it.
365template <>
366inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
367 art::Thread* thread,
368 JNIEnv* jnienv,
369 jclass class_being_redefined,
370 jobject loader,
371 const char* name,
372 jobject protection_domain,
373 jint class_data_len,
374 const unsigned char* class_data,
375 jint* new_class_data_len,
376 unsigned char** new_class_data) const {
377 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
378 thread,
379 jnienv,
380 class_being_redefined,
381 loader,
382 name,
383 protection_domain,
384 class_data_len,
385 class_data,
386 new_class_data_len,
387 new_class_data);
388}
389template <>
390inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
391 art::Thread* thread,
392 JNIEnv* jnienv,
393 jclass class_being_redefined,
394 jobject loader,
395 const char* name,
396 jobject protection_domain,
397 jint class_data_len,
398 const unsigned char* class_data,
399 jint* new_class_data_len,
400 unsigned char** new_class_data) const {
401 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
402 thread,
403 jnienv,
404 class_being_redefined,
405 loader,
406 name,
407 protection_domain,
408 class_data_len,
409 class_data,
410 new_class_data_len,
411 new_class_data);
412}
Alex Light40d87f42017-01-18 10:27:06 -0800413
Andreas Gampe983c1752017-01-23 19:46:56 -0800414template <ArtJvmtiEvent kEvent>
415inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
416 art::Thread* thread) {
417 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
418
419 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800420 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800421 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800422 }
423 return dispatch;
424}
425
Alex Light73afd322017-01-18 11:17:47 -0800426inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
427 bool union_value = false;
428 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700429 if (stored_env == nullptr) {
430 continue;
431 }
Alex Light73afd322017-01-18 11:17:47 -0800432 union_value |= stored_env->event_masks.global_event_mask.Test(event);
433 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
434 if (union_value) {
435 break;
436 }
437 }
438 global_mask.Set(event, union_value);
439}
440
441inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
442 const jvmtiCapabilities& caps,
443 bool added) {
444 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
445 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700446 return (added && caps.can_access_local_variables == 1) ||
447 (caps.can_retransform_classes == 1 &&
448 IsEventEnabledAnywhere(event) &&
449 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800450}
451
452inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
453 const jvmtiCapabilities& caps,
454 bool added) {
455 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
456 env->event_masks.HandleChangedCapabilities(caps, added);
457 if (caps.can_retransform_classes == 1) {
458 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
459 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
460 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700461 if (added && caps.can_access_local_variables == 1) {
462 HandleLocalAccessCapabilityAdded();
463 }
Alex Light73afd322017-01-18 11:17:47 -0800464 }
465}
466
Andreas Gampe77708d92016-10-07 11:48:21 -0700467} // namespace openjdkjvmti
468
Andreas Gampe06c42a52017-07-26 14:17:14 -0700469#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_