blob: af99233f90716fdd7e1bc200d26b5b7c39865e14 [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
17#ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
18#define ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
19
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"
Alex Lightb7edcda2017-04-27 13:20:31 -070024#include "ScopedLocalRef.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070025
26#include "art_jvmti.h"
27
28namespace openjdkjvmti {
29
Alex Light73afd322017-01-18 11:17:47 -080030static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
31 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
32 if (env->capabilities.can_retransform_classes) {
33 return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
34 } else {
35 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
36 }
37 } else {
38 return static_cast<ArtJvmtiEvent>(e);
39 }
Alex Light40d87f42017-01-18 10:27:06 -080040}
41
Andreas Gampe983c1752017-01-23 19:46:56 -080042namespace impl {
Andreas Gampe77708d92016-10-07 11:48:21 -070043
Andreas Gampe983c1752017-01-23 19:46:56 -080044// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070045
Andreas Gampe983c1752017-01-23 19:46:56 -080046#define FORALL_EVENT_TYPES(fn) \
47 fn(VMInit, ArtJvmtiEvent::kVmInit) \
48 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
49 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
50 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
51 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
52 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
53 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
54 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
55 fn(VMStart, ArtJvmtiEvent::kVmStart) \
56 fn(Exception, ArtJvmtiEvent::kException) \
57 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
58 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
59 fn(FramePop, ArtJvmtiEvent::kFramePop) \
60 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
61 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
62 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
63 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
64 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
65 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
66 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
67 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
68 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
69 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
70 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
71 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
72 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
73 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
74 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
75 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
76 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
77 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
78 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc)
79
80template <ArtJvmtiEvent kEvent>
81struct EventFnType {
82};
83
84#define EVENT_FN_TYPE(name, enum_name) \
85template <> \
86struct EventFnType<enum_name> { \
87 using type = decltype(jvmtiEventCallbacks().name); \
88};
89
90FORALL_EVENT_TYPES(EVENT_FN_TYPE)
91
92#undef EVENT_FN_TYPE
93
94template <ArtJvmtiEvent kEvent>
95ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
96
97#define GET_CALLBACK(name, enum_name) \
98template <> \
99ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
100 ArtJvmTiEnv* env) { \
101 if (env->event_callbacks == nullptr) { \
102 return nullptr; \
103 } \
104 return env->event_callbacks->name; \
Andreas Gampe77708d92016-10-07 11:48:21 -0700105}
106
Andreas Gampe983c1752017-01-23 19:46:56 -0800107FORALL_EVENT_TYPES(GET_CALLBACK)
Alex Light6ac57502017-01-19 15:05:06 -0800108
Andreas Gampe983c1752017-01-23 19:46:56 -0800109#undef GET_CALLBACK
110
111#undef FORALL_EVENT_TYPES
112
113} // namespace impl
114
115// C++ does not allow partial template function specialization. The dispatch for our separated
116// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Alex Light6ac57502017-01-19 15:05:06 -0800117// TODO Locking of some type!
Andreas Gampe983c1752017-01-23 19:46:56 -0800118template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800119inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800120 JNIEnv* jnienv,
121 jclass class_being_redefined,
122 jobject loader,
123 const char* name,
124 jobject protection_domain,
125 jint class_data_len,
126 const unsigned char* class_data,
127 jint* new_class_data_len,
128 unsigned char** new_class_data) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800129 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
130 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700131 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800132 jint current_len = class_data_len;
133 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
134 ArtJvmTiEnv* last_env = nullptr;
135 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700136 if (env == nullptr) {
137 continue;
138 }
Andreas Gampe983c1752017-01-23 19:46:56 -0800139 if (ShouldDispatch<kEvent>(env, thread)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700140 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
141 jnienv->ExceptionClear();
Alex Light440b5d92017-01-24 15:32:25 -0800142 jint new_len = 0;
143 unsigned char* new_data = nullptr;
Andreas Gampe983c1752017-01-23 19:46:56 -0800144 auto callback = impl::GetCallback<kEvent>(env);
Alex Light6ac57502017-01-19 15:05:06 -0800145 callback(env,
146 jnienv,
147 class_being_redefined,
148 loader,
149 name,
150 protection_domain,
151 current_len,
152 current_class_data,
153 &new_len,
154 &new_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700155 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
156 jnienv->Throw(thr.get());
157 }
Alex Light6ac57502017-01-19 15:05:06 -0800158 if (new_data != nullptr && new_data != current_class_data) {
159 // Destroy the data the last transformer made. We skip this if the previous state was the
160 // initial one since we don't know here which jvmtiEnv allocated it.
161 // NB Currently this doesn't matter since all allocations just go to malloc but in the
162 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
163 if (last_env != nullptr) {
164 last_env->Deallocate(current_class_data);
165 }
166 last_env = env;
167 current_class_data = new_data;
168 current_len = new_len;
169 }
170 }
171 }
172 if (last_env != nullptr) {
173 *new_class_data_len = current_len;
174 *new_class_data = current_class_data;
175 }
176}
177
Andreas Gampe983c1752017-01-23 19:46:56 -0800178// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
179// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800180
Andreas Gampe983c1752017-01-23 19:46:56 -0800181template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700182inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Andreas Gampe77708d92016-10-07 11:48:21 -0700183 for (ArtJvmTiEnv* env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700184 if (env != nullptr) {
185 DispatchEvent<kEvent, Args...>(env, thread, args...);
186 }
Andreas Gampea1705ea2017-03-28 20:12:13 -0700187 }
188}
189
Alex Lightb7edcda2017-04-27 13:20:31 -0700190// Events with JNIEnvs need to stash pending exceptions since they can cause new ones to be thrown.
191// In accordance with the JVMTI specification we allow exceptions originating from events to
192// overwrite the current exception, including exceptions originating from earlier events.
193// TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list of the
194// newest exception.
195template <ArtJvmtiEvent kEvent, typename ...Args>
196inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
197 for (ArtJvmTiEnv* env : envs) {
198 if (env != nullptr) {
199 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
200 jnienv->ExceptionClear();
201 DispatchEvent<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...);
202 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
203 jnienv->Throw(thr.get());
204 }
205 }
206 }
207}
208
Andreas Gampea1705ea2017-03-28 20:12:13 -0700209template <ArtJvmtiEvent kEvent, typename ...Args>
210inline void EventHandler::DispatchEvent(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
211 using FnType = void(jvmtiEnv*, Args...);
212 if (ShouldDispatch<kEvent>(env, thread)) {
213 FnType* callback = impl::GetCallback<kEvent>(env);
214 if (callback != nullptr) {
215 (*callback)(env, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700216 }
217 }
218}
219
Alex Light084fa372017-06-16 08:58:34 -0700220// Need to give custom specializations for FieldAccess and FieldModification since they need to
221// filter out which particular fields agents want to get notified on.
222// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
223// could make the system more performant.
224template <>
225inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFieldModification>(art::Thread* thread,
226 JNIEnv* jnienv,
227 jthread jni_thread,
228 jmethodID method,
229 jlocation location,
230 jclass field_klass,
231 jobject object,
232 jfieldID field,
233 char type_char,
234 jvalue val) const {
235 for (ArtJvmTiEnv* env : envs) {
236 if (env != nullptr &&
237 ShouldDispatch<ArtJvmtiEvent::kFieldModification>(env, thread) &&
238 env->modify_watched_fields.find(
239 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end()) {
240 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
241 jnienv->ExceptionClear();
242 auto callback = impl::GetCallback<ArtJvmtiEvent::kFieldModification>(env);
243 (*callback)(env,
244 jnienv,
245 jni_thread,
246 method,
247 location,
248 field_klass,
249 object,
250 field,
251 type_char,
252 val);
253 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
254 jnienv->Throw(thr.get());
255 }
256 }
257 }
258}
259
260template <>
261inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFieldAccess>(art::Thread* thread,
262 JNIEnv* jnienv,
263 jthread jni_thread,
264 jmethodID method,
265 jlocation location,
266 jclass field_klass,
267 jobject object,
268 jfieldID field) const {
269 for (ArtJvmTiEnv* env : envs) {
270 if (env != nullptr &&
271 ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
272 env->access_watched_fields.find(
273 art::jni::DecodeArtField(field)) != env->access_watched_fields.end()) {
274 ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
275 jnienv->ExceptionClear();
276 auto callback = impl::GetCallback<ArtJvmtiEvent::kFieldAccess>(env);
277 (*callback)(env, jnienv, jni_thread, method, location, field_klass, object, field);
278 if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
279 jnienv->Throw(thr.get());
280 }
281 }
282 }
283}
284
Alex Lightd78ddec2017-04-18 15:20:38 -0700285// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
286// variable.
287template <>
288inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
289 JNIEnv* jnienv,
290 jthread jni_thread,
291 jmethodID method,
292 void* cur_method,
293 void** new_method) const {
294 *new_method = cur_method;
295 for (ArtJvmTiEnv* env : envs) {
296 if (env != nullptr && ShouldDispatch<ArtJvmtiEvent::kNativeMethodBind>(env, thread)) {
297 auto callback = impl::GetCallback<ArtJvmtiEvent::kNativeMethodBind>(env);
298 (*callback)(env, jnienv, jni_thread, method, cur_method, new_method);
299 if (*new_method != nullptr) {
300 cur_method = *new_method;
301 }
302 }
303 }
304}
305
Andreas Gampe983c1752017-01-23 19:46:56 -0800306// C++ does not allow partial template function specialization. The dispatch for our separated
307// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
308// The following two DispatchEvent specializations dispatch to it.
309template <>
310inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
311 art::Thread* thread,
312 JNIEnv* jnienv,
313 jclass class_being_redefined,
314 jobject loader,
315 const char* name,
316 jobject protection_domain,
317 jint class_data_len,
318 const unsigned char* class_data,
319 jint* new_class_data_len,
320 unsigned char** new_class_data) const {
321 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
322 thread,
323 jnienv,
324 class_being_redefined,
325 loader,
326 name,
327 protection_domain,
328 class_data_len,
329 class_data,
330 new_class_data_len,
331 new_class_data);
332}
333template <>
334inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
335 art::Thread* thread,
336 JNIEnv* jnienv,
337 jclass class_being_redefined,
338 jobject loader,
339 const char* name,
340 jobject protection_domain,
341 jint class_data_len,
342 const unsigned char* class_data,
343 jint* new_class_data_len,
344 unsigned char** new_class_data) const {
345 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
346 thread,
347 jnienv,
348 class_being_redefined,
349 loader,
350 name,
351 protection_domain,
352 class_data_len,
353 class_data,
354 new_class_data_len,
355 new_class_data);
356}
Alex Light40d87f42017-01-18 10:27:06 -0800357
Andreas Gampe983c1752017-01-23 19:46:56 -0800358template <ArtJvmtiEvent kEvent>
359inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
360 art::Thread* thread) {
361 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
362
363 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800364 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800365 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800366 }
367 return dispatch;
368}
369
Alex Light73afd322017-01-18 11:17:47 -0800370inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
371 bool union_value = false;
372 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700373 if (stored_env == nullptr) {
374 continue;
375 }
Alex Light73afd322017-01-18 11:17:47 -0800376 union_value |= stored_env->event_masks.global_event_mask.Test(event);
377 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
378 if (union_value) {
379 break;
380 }
381 }
382 global_mask.Set(event, union_value);
383}
384
385inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
386 const jvmtiCapabilities& caps,
387 bool added) {
388 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
389 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
390 return caps.can_retransform_classes == 1 &&
391 IsEventEnabledAnywhere(event) &&
392 env->event_masks.IsEnabledAnywhere(event);
393}
394
395inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
396 const jvmtiCapabilities& caps,
397 bool added) {
398 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
399 env->event_masks.HandleChangedCapabilities(caps, added);
400 if (caps.can_retransform_classes == 1) {
401 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
402 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
403 }
404 }
405}
406
Andreas Gampe77708d92016-10-07 11:48:21 -0700407} // namespace openjdkjvmti
408
409#endif // ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_