blob: 74ffb845798c7a2e70c3d13a6d9fc45217c8c185 [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
Alex Lightb284f8d2017-11-21 00:00:48 +000049// Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash
50// pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI
51// specification we allow exceptions originating from events to overwrite the current exception,
52// including exceptions originating from earlier events.
53class ScopedEventDispatchEnvironment FINAL : public art::ValueObject {
54 public:
55 ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
56 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
57 }
58
59 explicit ScopedEventDispatchEnvironment(JNIEnv* env)
60 : env_(env),
61 throw_(env_, env_->ExceptionOccurred()) {
62 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
63 // The spec doesn't say how much local data should be there, so we just give 128 which seems
64 // likely to be enough for most cases.
65 env_->PushLocalFrame(128);
66 env_->ExceptionClear();
67 }
68
69 ~ScopedEventDispatchEnvironment() {
70 if (env_ != nullptr) {
71 if (throw_.get() != nullptr && !env_->ExceptionCheck()) {
72 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
73 // of the newest exception.
74 env_->Throw(throw_.get());
75 }
76 env_->PopLocalFrame(nullptr);
77 }
78 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
79 }
80
81 private:
82 JNIEnv* env_;
83 ScopedLocalRef<jthrowable> throw_;
84
85 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
86};
87
Andreas Gampe983c1752017-01-23 19:46:56 -080088// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070089
Andreas Gampe983c1752017-01-23 19:46:56 -080090#define FORALL_EVENT_TYPES(fn) \
91 fn(VMInit, ArtJvmtiEvent::kVmInit) \
92 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
93 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
94 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
95 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
96 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
97 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
98 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
99 fn(VMStart, ArtJvmtiEvent::kVmStart) \
100 fn(Exception, ArtJvmtiEvent::kException) \
101 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
102 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
103 fn(FramePop, ArtJvmtiEvent::kFramePop) \
104 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
105 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
106 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
107 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
108 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
109 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
110 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
111 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
112 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
113 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
114 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
115 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
116 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
117 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
118 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
119 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
120 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
121 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
Alex Light8c2b9292017-11-09 13:21:01 -0800122 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc) \
123 fn(DdmPublishChunk, ArtJvmtiEvent::kDdmPublishChunk)
Andreas Gampe983c1752017-01-23 19:46:56 -0800124
125template <ArtJvmtiEvent kEvent>
126struct EventFnType {
127};
128
Alex Light8c2b9292017-11-09 13:21:01 -0800129#define EVENT_FN_TYPE(name, enum_name) \
130template <> \
131struct EventFnType<enum_name> { \
132 using type = decltype(ArtJvmtiEventCallbacks().name); \
Andreas Gampe983c1752017-01-23 19:46:56 -0800133};
134
135FORALL_EVENT_TYPES(EVENT_FN_TYPE)
136
137#undef EVENT_FN_TYPE
138
Alex Lightb284f8d2017-11-21 00:00:48 +0000139#define MAKE_EVENT_HANDLER_FUNC(name, enum_name) \
140template<> \
141struct EventHandlerFunc<enum_name> { \
142 using EventFnType = typename impl::EventFnType<enum_name>::type; \
143 explicit EventHandlerFunc(ArtJvmTiEnv* env) \
144 : env_(env), \
145 fn_(env_->event_callbacks == nullptr ? nullptr : env_->event_callbacks->name) { } \
146 \
147 template <typename ...Args> \
148 ALWAYS_INLINE \
149 void ExecuteCallback(JNIEnv* jnienv, Args... args) const { \
150 if (fn_ != nullptr) { \
151 ScopedEventDispatchEnvironment sede(jnienv); \
152 DoExecute(jnienv, args...); \
153 } \
154 } \
155 \
156 template <typename ...Args> \
157 ALWAYS_INLINE \
158 void ExecuteCallback(Args... args) const { \
159 if (fn_ != nullptr) { \
160 ScopedEventDispatchEnvironment sede; \
161 DoExecute(args...); \
162 } \
163 } \
164 \
165 private: \
166 template <typename ...Args> \
167 ALWAYS_INLINE \
168 inline void DoExecute(Args... args) const { \
169 static_assert(std::is_same<EventFnType, void(*)(jvmtiEnv*, Args...)>::value, \
170 "Unexpected different type of ExecuteCallback"); \
171 fn_(env_, args...); \
172 } \
173 \
174 public: \
175 ArtJvmTiEnv* env_; \
176 EventFnType fn_; \
177};
Andreas Gampe983c1752017-01-23 19:46:56 -0800178
Alex Lightb284f8d2017-11-21 00:00:48 +0000179FORALL_EVENT_TYPES(MAKE_EVENT_HANDLER_FUNC)
Andreas Gampe77708d92016-10-07 11:48:21 -0700180
Alex Lightb284f8d2017-11-21 00:00:48 +0000181#undef MAKE_EVENT_HANDLER_FUNC
Andreas Gampe983c1752017-01-23 19:46:56 -0800182
183#undef FORALL_EVENT_TYPES
184
185} // namespace impl
186
Alex Lightb284f8d2017-11-21 00:00:48 +0000187template <ArtJvmtiEvent kEvent, typename ...Args>
188inline std::vector<impl::EventHandlerFunc<kEvent>> EventHandler::CollectEvents(art::Thread* thread,
189 Args... args) const {
Alex Light2a96fe82018-01-22 17:45:02 -0800190 art::ReaderMutexLock mu(thread, envs_lock_);
Alex Lightb284f8d2017-11-21 00:00:48 +0000191 std::vector<impl::EventHandlerFunc<kEvent>> handlers;
192 for (ArtJvmTiEnv* env : envs) {
193 if (ShouldDispatch<kEvent>(env, thread, args...)) {
194 impl::EventHandlerFunc<kEvent> h(env);
195 handlers.push_back(h);
196 }
197 }
198 return handlers;
199}
200
Andreas Gampe983c1752017-01-23 19:46:56 -0800201// C++ does not allow partial template function specialization. The dispatch for our separated
202// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Andreas Gampe983c1752017-01-23 19:46:56 -0800203template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800204inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800205 JNIEnv* jnienv,
206 jclass class_being_redefined,
207 jobject loader,
208 const char* name,
209 jobject protection_domain,
210 jint class_data_len,
211 const unsigned char* class_data,
212 jint* new_class_data_len,
213 unsigned char** new_class_data) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000214 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
Andreas Gampe983c1752017-01-23 19:46:56 -0800215 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
216 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700217 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800218 jint current_len = class_data_len;
219 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
Alex Lightb284f8d2017-11-21 00:00:48 +0000220 std::vector<impl::EventHandlerFunc<kEvent>> handlers =
221 CollectEvents<kEvent>(thread,
222 jnienv,
223 class_being_redefined,
224 loader,
225 name,
226 protection_domain,
227 class_data_len,
228 class_data,
229 new_class_data_len,
230 new_class_data);
Alex Light6ac57502017-01-19 15:05:06 -0800231 ArtJvmTiEnv* last_env = nullptr;
Alex Lightb284f8d2017-11-21 00:00:48 +0000232 for (const impl::EventHandlerFunc<kEvent>& event : handlers) {
Alex Light9df79b72017-09-12 08:57:31 -0700233 jint new_len = 0;
234 unsigned char* new_data = nullptr;
Alex Lightb284f8d2017-11-21 00:00:48 +0000235 ExecuteCallback<kEvent>(event,
236 jnienv,
237 class_being_redefined,
238 loader,
239 name,
240 protection_domain,
241 current_len,
242 static_cast<const unsigned char*>(current_class_data),
243 &new_len,
244 &new_data);
Alex Light9df79b72017-09-12 08:57:31 -0700245 if (new_data != nullptr && new_data != current_class_data) {
246 // Destroy the data the last transformer made. We skip this if the previous state was the
247 // initial one since we don't know here which jvmtiEnv allocated it.
248 // NB Currently this doesn't matter since all allocations just go to malloc but in the
249 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
250 if (last_env != nullptr) {
251 last_env->Deallocate(current_class_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700252 }
Alex Lightb284f8d2017-11-21 00:00:48 +0000253 last_env = event.env_;
Alex Light9df79b72017-09-12 08:57:31 -0700254 current_class_data = new_data;
255 current_len = new_len;
Alex Light6ac57502017-01-19 15:05:06 -0800256 }
257 }
258 if (last_env != nullptr) {
259 *new_class_data_len = current_len;
260 *new_class_data = current_class_data;
261 }
262}
263
Andreas Gampe983c1752017-01-23 19:46:56 -0800264// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
265// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800266
Andreas Gampe983c1752017-01-23 19:46:56 -0800267template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700268inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000269 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
Alex Light9df79b72017-09-12 08:57:31 -0700270 static_assert(!std::is_same<JNIEnv*,
271 typename std::decay_t<
272 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
273 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
274 DCHECK(thread == nullptr || !thread->IsExceptionPending());
Alex Lightb284f8d2017-11-21 00:00:48 +0000275 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, args...);
276 for (auto event : events) {
277 ExecuteCallback<kEvent>(event, args...);
Andreas Gampea1705ea2017-03-28 20:12:13 -0700278 }
279}
280
Alex Lightb7edcda2017-04-27 13:20:31 -0700281template <ArtJvmtiEvent kEvent, typename ...Args>
282inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000283 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
284 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
285 jnienv,
286 args...);
287 for (auto event : events) {
288 ExecuteCallback<kEvent>(event, jnienv, args...);
Alex Lightb7edcda2017-04-27 13:20:31 -0700289 }
290}
291
Andreas Gampea1705ea2017-03-28 20:12:13 -0700292template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700293inline void EventHandler::DispatchEventOnEnv(
294 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
295 DCHECK(env != nullptr);
296 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
Alex Lightb284f8d2017-11-21 00:00:48 +0000297 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
298 impl::EventHandlerFunc<kEvent> func(env);
299 ExecuteCallback<kEvent>(func, jnienv, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700300 }
301}
302
Alex Light9df79b72017-09-12 08:57:31 -0700303template <ArtJvmtiEvent kEvent, typename ...Args>
304inline void EventHandler::DispatchEventOnEnv(
305 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
306 static_assert(!std::is_same<JNIEnv*,
307 typename std::decay_t<
308 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
309 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
Alex Lightb284f8d2017-11-21 00:00:48 +0000310 DCHECK(env != nullptr);
311 if (ShouldDispatch<kEvent, Args...>(env, thread, args...)) {
312 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
313 impl::EventHandlerFunc<kEvent> func(env);
314 ExecuteCallback<kEvent>(func, args...);
Alex Light9df79b72017-09-12 08:57:31 -0700315 }
316}
317
Alex Lightb284f8d2017-11-21 00:00:48 +0000318template <ArtJvmtiEvent kEvent, typename ...Args>
319inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
320 handler.ExecuteCallback(args...);
321}
322
323template <ArtJvmtiEvent kEvent, typename ...Args>
324inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
325 JNIEnv* jnienv,
326 Args... args) {
327 handler.ExecuteCallback(jnienv, args...);
328}
329
Alex Light9df79b72017-09-12 08:57:31 -0700330// Events that need custom logic for if we send the event but are otherwise normal. This includes
331// the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
332
Alex Lighta26e3492017-06-27 17:55:37 -0700333// Need to give custom specializations for Breakpoint since it needs to filter out which particular
334// methods/dex_pcs agents get notified on.
335template <>
Alex Light9df79b72017-09-12 08:57:31 -0700336inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
337 ArtJvmTiEnv* env,
338 art::Thread* thread,
339 JNIEnv* jnienv ATTRIBUTE_UNUSED,
340 jthread jni_thread ATTRIBUTE_UNUSED,
341 jmethodID jmethod,
342 jlocation location) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700343 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Lighta26e3492017-06-27 17:55:37 -0700344 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
Alex Light9df79b72017-09-12 08:57:31 -0700345 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
346 env->breakpoints.find({method, location}) != env->breakpoints.end();
Alex Lighta26e3492017-06-27 17:55:37 -0700347}
348
Alex Lighte814f9d2017-07-31 16:14:39 -0700349template <>
Alex Light9df79b72017-09-12 08:57:31 -0700350inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
351 ArtJvmTiEnv* env,
Alex Lighte814f9d2017-07-31 16:14:39 -0700352 art::Thread* thread,
Alex Light9df79b72017-09-12 08:57:31 -0700353 JNIEnv* jnienv ATTRIBUTE_UNUSED,
354 jthread jni_thread ATTRIBUTE_UNUSED,
355 jmethodID jmethod ATTRIBUTE_UNUSED,
356 jboolean is_exception ATTRIBUTE_UNUSED,
Alex Lighte814f9d2017-07-31 16:14:39 -0700357 const art::ShadowFrame* frame) const {
Alex Light9df79b72017-09-12 08:57:31 -0700358 // Search for the frame. Do this before checking if we need to send the event so that we don't
359 // have to deal with use-after-free or the frames being reallocated later.
Alex Lightb6106d52017-10-18 15:02:15 -0700360 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700361 return env->notify_frames.erase(frame) != 0 &&
362 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
Alex Lighte814f9d2017-07-31 16:14:39 -0700363}
364
Alex Light084fa372017-06-16 08:58:34 -0700365// Need to give custom specializations for FieldAccess and FieldModification since they need to
366// filter out which particular fields agents want to get notified on.
367// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
368// could make the system more performant.
369template <>
Alex Light9df79b72017-09-12 08:57:31 -0700370inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
371 ArtJvmTiEnv* env,
372 art::Thread* thread,
373 JNIEnv* jnienv ATTRIBUTE_UNUSED,
374 jthread jni_thread ATTRIBUTE_UNUSED,
375 jmethodID method ATTRIBUTE_UNUSED,
376 jlocation location ATTRIBUTE_UNUSED,
377 jclass field_klass ATTRIBUTE_UNUSED,
378 jobject object ATTRIBUTE_UNUSED,
379 jfieldID field,
380 char type_char ATTRIBUTE_UNUSED,
381 jvalue val ATTRIBUTE_UNUSED) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700382 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700383 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
384 env->modify_watched_fields.find(
385 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
Alex Light084fa372017-06-16 08:58:34 -0700386}
387
388template <>
Alex Light9df79b72017-09-12 08:57:31 -0700389inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
390 ArtJvmTiEnv* env,
391 art::Thread* thread,
392 JNIEnv* jnienv ATTRIBUTE_UNUSED,
393 jthread jni_thread ATTRIBUTE_UNUSED,
394 jmethodID method ATTRIBUTE_UNUSED,
395 jlocation location ATTRIBUTE_UNUSED,
396 jclass field_klass ATTRIBUTE_UNUSED,
397 jobject object ATTRIBUTE_UNUSED,
398 jfieldID field) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700399 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700400 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
401 env->access_watched_fields.find(
402 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
403}
404
405// Need to give custom specializations for FramePop since it needs to filter out which particular
406// agents get the event. This specialization gets an extra argument so we can determine which (if
407// any) environments have the frame pop.
408// TODO It might be useful to use more template magic to have this only define ShouldDispatch or
409// something.
410template <>
411inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
Alex Lightb284f8d2017-11-21 00:00:48 +0000412 impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
Alex Light9df79b72017-09-12 08:57:31 -0700413 JNIEnv* jnienv,
414 jthread jni_thread,
415 jmethodID jmethod,
416 jboolean is_exception,
417 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
Alex Lightb284f8d2017-11-21 00:00:48 +0000418 ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
Alex Light084fa372017-06-16 08:58:34 -0700419}
420
Alex Lightd78ddec2017-04-18 15:20:38 -0700421// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
422// variable.
423template <>
424inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
425 JNIEnv* jnienv,
426 jthread jni_thread,
427 jmethodID method,
428 void* cur_method,
429 void** new_method) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000430 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
431 std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
432 CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
433 jnienv,
434 jni_thread,
435 method,
436 cur_method,
437 new_method);
Alex Lightd78ddec2017-04-18 15:20:38 -0700438 *new_method = cur_method;
Alex Lightb284f8d2017-11-21 00:00:48 +0000439 for (auto event : events) {
440 *new_method = cur_method;
441 ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
442 jnienv,
443 jni_thread,
444 method,
445 cur_method,
446 new_method);
447 if (*new_method != nullptr) {
448 cur_method = *new_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700449 }
450 }
Alex Light9df79b72017-09-12 08:57:31 -0700451 *new_method = cur_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700452}
453
Andreas Gampe983c1752017-01-23 19:46:56 -0800454// C++ does not allow partial template function specialization. The dispatch for our separated
455// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
456// The following two DispatchEvent specializations dispatch to it.
457template <>
458inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
459 art::Thread* thread,
460 JNIEnv* jnienv,
461 jclass class_being_redefined,
462 jobject loader,
463 const char* name,
464 jobject protection_domain,
465 jint class_data_len,
466 const unsigned char* class_data,
467 jint* new_class_data_len,
468 unsigned char** new_class_data) const {
469 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
470 thread,
471 jnienv,
472 class_being_redefined,
473 loader,
474 name,
475 protection_domain,
476 class_data_len,
477 class_data,
478 new_class_data_len,
479 new_class_data);
480}
Alex Light9df79b72017-09-12 08:57:31 -0700481
Andreas Gampe983c1752017-01-23 19:46:56 -0800482template <>
483inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
484 art::Thread* thread,
485 JNIEnv* jnienv,
486 jclass class_being_redefined,
487 jobject loader,
488 const char* name,
489 jobject protection_domain,
490 jint class_data_len,
491 const unsigned char* class_data,
492 jint* new_class_data_len,
493 unsigned char** new_class_data) const {
494 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
495 thread,
496 jnienv,
497 class_being_redefined,
498 loader,
499 name,
500 protection_domain,
501 class_data_len,
502 class_data,
503 new_class_data_len,
504 new_class_data);
505}
Alex Light40d87f42017-01-18 10:27:06 -0800506
Andreas Gampe983c1752017-01-23 19:46:56 -0800507template <ArtJvmtiEvent kEvent>
Alex Lightb284f8d2017-11-21 00:00:48 +0000508inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800509 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
510
511 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800512 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800513 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800514 }
515 return dispatch;
516}
517
Alex Light9df79b72017-09-12 08:57:31 -0700518template <ArtJvmtiEvent kEvent, typename ...Args>
519inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
520 art::Thread* thread,
521 Args... args ATTRIBUTE_UNUSED) const {
522 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
523 void(*)(jvmtiEnv*, Args...)>::value,
524 "Unexpected different type of shouldDispatch");
525
526 return ShouldDispatchOnThread<kEvent>(env, thread);
527}
528
Alex Light73afd322017-01-18 11:17:47 -0800529inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
Alex Light2a96fe82018-01-22 17:45:02 -0800530 art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
Alex Lightb284f8d2017-11-21 00:00:48 +0000531 RecalculateGlobalEventMaskLocked(event);
532}
533
534inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) {
Alex Light73afd322017-01-18 11:17:47 -0800535 bool union_value = false;
536 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700537 if (stored_env == nullptr) {
538 continue;
539 }
Alex Light73afd322017-01-18 11:17:47 -0800540 union_value |= stored_env->event_masks.global_event_mask.Test(event);
541 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
542 if (union_value) {
543 break;
544 }
545 }
546 global_mask.Set(event, union_value);
547}
548
549inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
550 const jvmtiCapabilities& caps,
551 bool added) {
552 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
553 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700554 return (added && caps.can_access_local_variables == 1) ||
Alex Light0fa17862017-10-24 13:43:05 -0700555 caps.can_generate_breakpoint_events == 1 ||
Alex Lightbebd7bd2017-07-25 14:05:52 -0700556 (caps.can_retransform_classes == 1 &&
557 IsEventEnabledAnywhere(event) &&
558 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800559}
560
561inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
562 const jvmtiCapabilities& caps,
563 bool added) {
564 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
565 env->event_masks.HandleChangedCapabilities(caps, added);
566 if (caps.can_retransform_classes == 1) {
567 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
568 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
569 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700570 if (added && caps.can_access_local_variables == 1) {
571 HandleLocalAccessCapabilityAdded();
572 }
Alex Light0fa17862017-10-24 13:43:05 -0700573 if (caps.can_generate_breakpoint_events == 1) {
574 HandleBreakpointEventsChanged(added);
575 }
Alex Light73afd322017-01-18 11:17:47 -0800576 }
577}
578
Andreas Gampe77708d92016-10-07 11:48:21 -0700579} // namespace openjdkjvmti
580
Andreas Gampe06c42a52017-07-26 14:17:14 -0700581#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_