blob: ca66556bb0b3191c68a50568bd58a1e571e2f5e8 [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"
Vladimir Markoa3ad0cd2018-05-04 10:06:38 +010026#include "jni/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 Light0aa7a5a2018-10-10 15:58:14 +000029#include "stack.h"
Alex Lighta26e3492017-06-27 17:55:37 -070030#include "ti_breakpoint.h"
Alex Light0aa7a5a2018-10-10 15:58:14 +000031#include "ti_thread.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070032
33#include "art_jvmti.h"
34
35namespace openjdkjvmti {
36
Alex Light73afd322017-01-18 11:17:47 -080037static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
38 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
39 if (env->capabilities.can_retransform_classes) {
40 return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
41 } else {
42 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
43 }
44 } else {
45 return static_cast<ArtJvmtiEvent>(e);
46 }
Alex Light40d87f42017-01-18 10:27:06 -080047}
48
Andreas Gampe983c1752017-01-23 19:46:56 -080049namespace impl {
Andreas Gampe77708d92016-10-07 11:48:21 -070050
Alex Lightb284f8d2017-11-21 00:00:48 +000051// Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash
52// pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI
53// specification we allow exceptions originating from events to overwrite the current exception,
54// including exceptions originating from earlier events.
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010055class ScopedEventDispatchEnvironment final : public art::ValueObject {
Alex Lightb284f8d2017-11-21 00:00:48 +000056 public:
57 ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
58 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
59 }
60
61 explicit ScopedEventDispatchEnvironment(JNIEnv* env)
62 : env_(env),
63 throw_(env_, env_->ExceptionOccurred()) {
64 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
65 // The spec doesn't say how much local data should be there, so we just give 128 which seems
66 // likely to be enough for most cases.
67 env_->PushLocalFrame(128);
68 env_->ExceptionClear();
69 }
70
71 ~ScopedEventDispatchEnvironment() {
72 if (env_ != nullptr) {
73 if (throw_.get() != nullptr && !env_->ExceptionCheck()) {
74 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
75 // of the newest exception.
76 env_->Throw(throw_.get());
77 }
78 env_->PopLocalFrame(nullptr);
79 }
80 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
81 }
82
83 private:
84 JNIEnv* env_;
85 ScopedLocalRef<jthrowable> throw_;
86
87 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
88};
89
Andreas Gampe983c1752017-01-23 19:46:56 -080090// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070091
Andreas Gampe983c1752017-01-23 19:46:56 -080092#define FORALL_EVENT_TYPES(fn) \
93 fn(VMInit, ArtJvmtiEvent::kVmInit) \
94 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
95 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
96 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
97 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
98 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
99 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
100 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
101 fn(VMStart, ArtJvmtiEvent::kVmStart) \
102 fn(Exception, ArtJvmtiEvent::kException) \
103 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
104 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
105 fn(FramePop, ArtJvmtiEvent::kFramePop) \
106 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
107 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
108 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
109 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
110 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
111 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
112 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
113 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
114 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
115 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
116 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
117 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
118 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
119 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
120 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
121 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
122 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
123 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
Alex Light8c2b9292017-11-09 13:21:01 -0800124 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc) \
125 fn(DdmPublishChunk, ArtJvmtiEvent::kDdmPublishChunk)
Andreas Gampe983c1752017-01-23 19:46:56 -0800126
127template <ArtJvmtiEvent kEvent>
128struct EventFnType {
129};
130
Alex Light8c2b9292017-11-09 13:21:01 -0800131#define EVENT_FN_TYPE(name, enum_name) \
132template <> \
133struct EventFnType<enum_name> { \
134 using type = decltype(ArtJvmtiEventCallbacks().name); \
Andreas Gampe983c1752017-01-23 19:46:56 -0800135};
136
137FORALL_EVENT_TYPES(EVENT_FN_TYPE)
138
139#undef EVENT_FN_TYPE
140
Alex Lightb284f8d2017-11-21 00:00:48 +0000141#define MAKE_EVENT_HANDLER_FUNC(name, enum_name) \
142template<> \
143struct EventHandlerFunc<enum_name> { \
144 using EventFnType = typename impl::EventFnType<enum_name>::type; \
145 explicit EventHandlerFunc(ArtJvmTiEnv* env) \
146 : env_(env), \
147 fn_(env_->event_callbacks == nullptr ? nullptr : env_->event_callbacks->name) { } \
148 \
149 template <typename ...Args> \
150 ALWAYS_INLINE \
151 void ExecuteCallback(JNIEnv* jnienv, Args... args) const { \
152 if (fn_ != nullptr) { \
153 ScopedEventDispatchEnvironment sede(jnienv); \
154 DoExecute(jnienv, args...); \
155 } \
156 } \
157 \
158 template <typename ...Args> \
159 ALWAYS_INLINE \
160 void ExecuteCallback(Args... args) const { \
161 if (fn_ != nullptr) { \
162 ScopedEventDispatchEnvironment sede; \
163 DoExecute(args...); \
164 } \
165 } \
166 \
167 private: \
168 template <typename ...Args> \
169 ALWAYS_INLINE \
170 inline void DoExecute(Args... args) const { \
171 static_assert(std::is_same<EventFnType, void(*)(jvmtiEnv*, Args...)>::value, \
172 "Unexpected different type of ExecuteCallback"); \
173 fn_(env_, args...); \
174 } \
175 \
176 public: \
177 ArtJvmTiEnv* env_; \
178 EventFnType fn_; \
179};
Andreas Gampe983c1752017-01-23 19:46:56 -0800180
Alex Lightb284f8d2017-11-21 00:00:48 +0000181FORALL_EVENT_TYPES(MAKE_EVENT_HANDLER_FUNC)
Andreas Gampe77708d92016-10-07 11:48:21 -0700182
Alex Lightb284f8d2017-11-21 00:00:48 +0000183#undef MAKE_EVENT_HANDLER_FUNC
Andreas Gampe983c1752017-01-23 19:46:56 -0800184
185#undef FORALL_EVENT_TYPES
186
187} // namespace impl
188
Alex Lightb284f8d2017-11-21 00:00:48 +0000189template <ArtJvmtiEvent kEvent, typename ...Args>
190inline std::vector<impl::EventHandlerFunc<kEvent>> EventHandler::CollectEvents(art::Thread* thread,
191 Args... args) const {
Alex Light2a96fe82018-01-22 17:45:02 -0800192 art::ReaderMutexLock mu(thread, envs_lock_);
Alex Lightb284f8d2017-11-21 00:00:48 +0000193 std::vector<impl::EventHandlerFunc<kEvent>> handlers;
194 for (ArtJvmTiEnv* env : envs) {
195 if (ShouldDispatch<kEvent>(env, thread, args...)) {
196 impl::EventHandlerFunc<kEvent> h(env);
197 handlers.push_back(h);
198 }
199 }
200 return handlers;
201}
202
Andreas Gampe983c1752017-01-23 19:46:56 -0800203// C++ does not allow partial template function specialization. The dispatch for our separated
204// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Andreas Gampe983c1752017-01-23 19:46:56 -0800205template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800206inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800207 JNIEnv* jnienv,
208 jclass class_being_redefined,
209 jobject loader,
210 const char* name,
211 jobject protection_domain,
212 jint class_data_len,
213 const unsigned char* class_data,
214 jint* new_class_data_len,
215 unsigned char** new_class_data) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000216 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
Andreas Gampe983c1752017-01-23 19:46:56 -0800217 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
218 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700219 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800220 jint current_len = class_data_len;
221 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
Alex Lightb284f8d2017-11-21 00:00:48 +0000222 std::vector<impl::EventHandlerFunc<kEvent>> handlers =
223 CollectEvents<kEvent>(thread,
224 jnienv,
225 class_being_redefined,
226 loader,
227 name,
228 protection_domain,
229 class_data_len,
230 class_data,
231 new_class_data_len,
232 new_class_data);
Alex Light6ac57502017-01-19 15:05:06 -0800233 ArtJvmTiEnv* last_env = nullptr;
Alex Lightb284f8d2017-11-21 00:00:48 +0000234 for (const impl::EventHandlerFunc<kEvent>& event : handlers) {
Alex Light9df79b72017-09-12 08:57:31 -0700235 jint new_len = 0;
236 unsigned char* new_data = nullptr;
Alex Lightb284f8d2017-11-21 00:00:48 +0000237 ExecuteCallback<kEvent>(event,
238 jnienv,
239 class_being_redefined,
240 loader,
241 name,
242 protection_domain,
243 current_len,
244 static_cast<const unsigned char*>(current_class_data),
245 &new_len,
246 &new_data);
Alex Light9df79b72017-09-12 08:57:31 -0700247 if (new_data != nullptr && new_data != current_class_data) {
248 // Destroy the data the last transformer made. We skip this if the previous state was the
249 // initial one since we don't know here which jvmtiEnv allocated it.
250 // NB Currently this doesn't matter since all allocations just go to malloc but in the
251 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
252 if (last_env != nullptr) {
253 last_env->Deallocate(current_class_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700254 }
Alex Lightb284f8d2017-11-21 00:00:48 +0000255 last_env = event.env_;
Alex Light9df79b72017-09-12 08:57:31 -0700256 current_class_data = new_data;
257 current_len = new_len;
Alex Light6ac57502017-01-19 15:05:06 -0800258 }
259 }
260 if (last_env != nullptr) {
261 *new_class_data_len = current_len;
262 *new_class_data = current_class_data;
263 }
264}
265
Andreas Gampe983c1752017-01-23 19:46:56 -0800266// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
267// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800268
Andreas Gampe983c1752017-01-23 19:46:56 -0800269template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700270inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000271 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
Alex Light9df79b72017-09-12 08:57:31 -0700272 static_assert(!std::is_same<JNIEnv*,
273 typename std::decay_t<
274 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
275 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
276 DCHECK(thread == nullptr || !thread->IsExceptionPending());
Alex Lightb284f8d2017-11-21 00:00:48 +0000277 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, args...);
278 for (auto event : events) {
279 ExecuteCallback<kEvent>(event, args...);
Andreas Gampea1705ea2017-03-28 20:12:13 -0700280 }
281}
282
Alex Lightb7edcda2017-04-27 13:20:31 -0700283template <ArtJvmtiEvent kEvent, typename ...Args>
284inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000285 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
286 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
287 jnienv,
288 args...);
289 for (auto event : events) {
290 ExecuteCallback<kEvent>(event, jnienv, args...);
Alex Lightb7edcda2017-04-27 13:20:31 -0700291 }
292}
293
Andreas Gampea1705ea2017-03-28 20:12:13 -0700294template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700295inline void EventHandler::DispatchEventOnEnv(
296 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
297 DCHECK(env != nullptr);
298 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
Alex Lightb284f8d2017-11-21 00:00:48 +0000299 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
300 impl::EventHandlerFunc<kEvent> func(env);
301 ExecuteCallback<kEvent>(func, jnienv, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700302 }
303}
304
Alex Light9df79b72017-09-12 08:57:31 -0700305template <ArtJvmtiEvent kEvent, typename ...Args>
306inline void EventHandler::DispatchEventOnEnv(
307 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
308 static_assert(!std::is_same<JNIEnv*,
309 typename std::decay_t<
310 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
311 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
Alex Lightb284f8d2017-11-21 00:00:48 +0000312 DCHECK(env != nullptr);
313 if (ShouldDispatch<kEvent, Args...>(env, thread, args...)) {
314 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
315 impl::EventHandlerFunc<kEvent> func(env);
316 ExecuteCallback<kEvent>(func, args...);
Alex Light9df79b72017-09-12 08:57:31 -0700317 }
318}
319
Alex Lightb284f8d2017-11-21 00:00:48 +0000320template <ArtJvmtiEvent kEvent, typename ...Args>
321inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
322 handler.ExecuteCallback(args...);
323}
324
325template <ArtJvmtiEvent kEvent, typename ...Args>
326inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
327 JNIEnv* jnienv,
328 Args... args) {
329 handler.ExecuteCallback(jnienv, args...);
330}
331
Alex Light9df79b72017-09-12 08:57:31 -0700332// Events that need custom logic for if we send the event but are otherwise normal. This includes
333// the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
334
Alex Lighta26e3492017-06-27 17:55:37 -0700335// Need to give custom specializations for Breakpoint since it needs to filter out which particular
336// methods/dex_pcs agents get notified on.
337template <>
Alex Light9df79b72017-09-12 08:57:31 -0700338inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
339 ArtJvmTiEnv* env,
340 art::Thread* thread,
341 JNIEnv* jnienv ATTRIBUTE_UNUSED,
342 jthread jni_thread ATTRIBUTE_UNUSED,
343 jmethodID jmethod,
344 jlocation location) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700345 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Lighta26e3492017-06-27 17:55:37 -0700346 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
Alex Light9df79b72017-09-12 08:57:31 -0700347 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
348 env->breakpoints.find({method, location}) != env->breakpoints.end();
Alex Lighta26e3492017-06-27 17:55:37 -0700349}
350
Alex Lighte814f9d2017-07-31 16:14:39 -0700351template <>
Alex Light9df79b72017-09-12 08:57:31 -0700352inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
353 ArtJvmTiEnv* env,
Alex Lighte814f9d2017-07-31 16:14:39 -0700354 art::Thread* thread,
Alex Light9df79b72017-09-12 08:57:31 -0700355 JNIEnv* jnienv ATTRIBUTE_UNUSED,
356 jthread jni_thread ATTRIBUTE_UNUSED,
357 jmethodID jmethod ATTRIBUTE_UNUSED,
358 jboolean is_exception ATTRIBUTE_UNUSED,
Alex Lighte814f9d2017-07-31 16:14:39 -0700359 const art::ShadowFrame* frame) const {
Alex Light9df79b72017-09-12 08:57:31 -0700360 // Search for the frame. Do this before checking if we need to send the event so that we don't
361 // have to deal with use-after-free or the frames being reallocated later.
Alex Lightb6106d52017-10-18 15:02:15 -0700362 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700363 return env->notify_frames.erase(frame) != 0 &&
Alex Light0aa7a5a2018-10-10 15:58:14 +0000364 !frame->GetForcePopFrame() &&
Alex Light9df79b72017-09-12 08:57:31 -0700365 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
Alex Lighte814f9d2017-07-31 16:14:39 -0700366}
367
Alex Light084fa372017-06-16 08:58:34 -0700368// Need to give custom specializations for FieldAccess and FieldModification since they need to
369// filter out which particular fields agents want to get notified on.
370// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
371// could make the system more performant.
372template <>
Alex Light9df79b72017-09-12 08:57:31 -0700373inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
374 ArtJvmTiEnv* env,
375 art::Thread* thread,
376 JNIEnv* jnienv ATTRIBUTE_UNUSED,
377 jthread jni_thread ATTRIBUTE_UNUSED,
378 jmethodID method ATTRIBUTE_UNUSED,
379 jlocation location ATTRIBUTE_UNUSED,
380 jclass field_klass ATTRIBUTE_UNUSED,
381 jobject object ATTRIBUTE_UNUSED,
382 jfieldID field,
383 char type_char ATTRIBUTE_UNUSED,
384 jvalue val ATTRIBUTE_UNUSED) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700385 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700386 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
387 env->modify_watched_fields.find(
388 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
Alex Light084fa372017-06-16 08:58:34 -0700389}
390
391template <>
Alex Light9df79b72017-09-12 08:57:31 -0700392inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
393 ArtJvmTiEnv* env,
394 art::Thread* thread,
395 JNIEnv* jnienv ATTRIBUTE_UNUSED,
396 jthread jni_thread ATTRIBUTE_UNUSED,
397 jmethodID method ATTRIBUTE_UNUSED,
398 jlocation location ATTRIBUTE_UNUSED,
399 jclass field_klass ATTRIBUTE_UNUSED,
400 jobject object ATTRIBUTE_UNUSED,
401 jfieldID field) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700402 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700403 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
404 env->access_watched_fields.find(
405 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
406}
407
408// Need to give custom specializations for FramePop since it needs to filter out which particular
409// agents get the event. This specialization gets an extra argument so we can determine which (if
410// any) environments have the frame pop.
411// TODO It might be useful to use more template magic to have this only define ShouldDispatch or
412// something.
413template <>
414inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
Alex Lightb284f8d2017-11-21 00:00:48 +0000415 impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
Alex Light9df79b72017-09-12 08:57:31 -0700416 JNIEnv* jnienv,
417 jthread jni_thread,
418 jmethodID jmethod,
419 jboolean is_exception,
420 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
Alex Lightb284f8d2017-11-21 00:00:48 +0000421 ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
Alex Light084fa372017-06-16 08:58:34 -0700422}
423
Alex Light0aa7a5a2018-10-10 15:58:14 +0000424struct ScopedDisablePopFrame {
425 public:
426 explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) {
427 art::Locks::mutator_lock_->AssertSharedHeld(thread_);
428 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
429 JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_);
430 current_top_frame_ = art::StackVisitor::ComputeNumFrames(
431 thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
432 old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
433 data->disable_pop_frame_depth = current_top_frame_;
434 DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
435 current_top_frame_ > old_disable_frame_pop_depth_)
436 << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
437 }
438
439 ~ScopedDisablePopFrame() {
440 art::Locks::mutator_lock_->AssertSharedHeld(thread_);
441 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
442 JvmtiGlobalTLSData* data = ThreadUtil::GetGlobalTLSData(thread_);
443 DCHECK_EQ(data->disable_pop_frame_depth, current_top_frame_);
444 data->disable_pop_frame_depth = old_disable_frame_pop_depth_;
445 }
446
447 private:
448 art::Thread* thread_;
449 size_t current_top_frame_;
450 size_t old_disable_frame_pop_depth_;
451};
452// We want to prevent the use of PopFrame when reporting either of these events.
453template <ArtJvmtiEvent kEvent>
454inline void EventHandler::DispatchClassLoadOrPrepareEvent(art::Thread* thread,
455 JNIEnv* jnienv,
456 jthread jni_thread,
457 jclass klass) const {
458 ScopedDisablePopFrame sdpf(thread);
459 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
460 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
461 jnienv,
462 jni_thread,
463 klass);
464
465 for (auto event : events) {
466 ExecuteCallback<kEvent>(event, jnienv, jni_thread, klass);
467 }
468}
469
470template <>
471inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassLoad>(art::Thread* thread,
472 JNIEnv* jnienv,
473 jthread jni_thread,
474 jclass klass) const {
475 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassLoad>(thread, jnienv, jni_thread, klass);
476}
477template <>
478inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassPrepare>(art::Thread* thread,
479 JNIEnv* jnienv,
480 jthread jni_thread,
481 jclass klass) const {
482 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassPrepare>(thread, jnienv, jni_thread, klass);
483}
484
Alex Lightd78ddec2017-04-18 15:20:38 -0700485// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
486// variable.
487template <>
488inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
489 JNIEnv* jnienv,
490 jthread jni_thread,
491 jmethodID method,
492 void* cur_method,
493 void** new_method) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000494 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
495 std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
496 CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
497 jnienv,
498 jni_thread,
499 method,
500 cur_method,
501 new_method);
Alex Lightd78ddec2017-04-18 15:20:38 -0700502 *new_method = cur_method;
Alex Lightb284f8d2017-11-21 00:00:48 +0000503 for (auto event : events) {
504 *new_method = cur_method;
505 ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
506 jnienv,
507 jni_thread,
508 method,
509 cur_method,
510 new_method);
511 if (*new_method != nullptr) {
512 cur_method = *new_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700513 }
514 }
Alex Light9df79b72017-09-12 08:57:31 -0700515 *new_method = cur_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700516}
517
Andreas Gampe983c1752017-01-23 19:46:56 -0800518// C++ does not allow partial template function specialization. The dispatch for our separated
519// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
520// The following two DispatchEvent specializations dispatch to it.
521template <>
522inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
523 art::Thread* thread,
524 JNIEnv* jnienv,
525 jclass class_being_redefined,
526 jobject loader,
527 const char* name,
528 jobject protection_domain,
529 jint class_data_len,
530 const unsigned char* class_data,
531 jint* new_class_data_len,
532 unsigned char** new_class_data) const {
533 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
534 thread,
535 jnienv,
536 class_being_redefined,
537 loader,
538 name,
539 protection_domain,
540 class_data_len,
541 class_data,
542 new_class_data_len,
543 new_class_data);
544}
Alex Light9df79b72017-09-12 08:57:31 -0700545
Andreas Gampe983c1752017-01-23 19:46:56 -0800546template <>
547inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
548 art::Thread* thread,
549 JNIEnv* jnienv,
550 jclass class_being_redefined,
551 jobject loader,
552 const char* name,
553 jobject protection_domain,
554 jint class_data_len,
555 const unsigned char* class_data,
556 jint* new_class_data_len,
557 unsigned char** new_class_data) const {
558 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
559 thread,
560 jnienv,
561 class_being_redefined,
562 loader,
563 name,
564 protection_domain,
565 class_data_len,
566 class_data,
567 new_class_data_len,
568 new_class_data);
569}
Alex Light40d87f42017-01-18 10:27:06 -0800570
Andreas Gampe983c1752017-01-23 19:46:56 -0800571template <ArtJvmtiEvent kEvent>
Alex Lightb284f8d2017-11-21 00:00:48 +0000572inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800573 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
574
575 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800576 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800577 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800578 }
579 return dispatch;
580}
581
Alex Light9df79b72017-09-12 08:57:31 -0700582template <ArtJvmtiEvent kEvent, typename ...Args>
583inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
584 art::Thread* thread,
585 Args... args ATTRIBUTE_UNUSED) const {
586 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
587 void(*)(jvmtiEnv*, Args...)>::value,
588 "Unexpected different type of shouldDispatch");
589
590 return ShouldDispatchOnThread<kEvent>(env, thread);
591}
592
Alex Light73afd322017-01-18 11:17:47 -0800593inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
Alex Light2a96fe82018-01-22 17:45:02 -0800594 art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
Alex Lightb284f8d2017-11-21 00:00:48 +0000595 RecalculateGlobalEventMaskLocked(event);
596}
597
598inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) {
Alex Light73afd322017-01-18 11:17:47 -0800599 bool union_value = false;
600 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700601 if (stored_env == nullptr) {
602 continue;
603 }
Alex Light73afd322017-01-18 11:17:47 -0800604 union_value |= stored_env->event_masks.global_event_mask.Test(event);
605 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
606 if (union_value) {
607 break;
608 }
609 }
610 global_mask.Set(event, union_value);
611}
612
613inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
614 const jvmtiCapabilities& caps,
615 bool added) {
616 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
617 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700618 return (added && caps.can_access_local_variables == 1) ||
Alex Light0fa17862017-10-24 13:43:05 -0700619 caps.can_generate_breakpoint_events == 1 ||
Alex Light0aa7a5a2018-10-10 15:58:14 +0000620 caps.can_pop_frame == 1 ||
Alex Lightbebd7bd2017-07-25 14:05:52 -0700621 (caps.can_retransform_classes == 1 &&
622 IsEventEnabledAnywhere(event) &&
623 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800624}
625
626inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
627 const jvmtiCapabilities& caps,
628 bool added) {
629 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
630 env->event_masks.HandleChangedCapabilities(caps, added);
631 if (caps.can_retransform_classes == 1) {
632 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
633 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
634 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700635 if (added && caps.can_access_local_variables == 1) {
636 HandleLocalAccessCapabilityAdded();
637 }
Alex Light0fa17862017-10-24 13:43:05 -0700638 if (caps.can_generate_breakpoint_events == 1) {
639 HandleBreakpointEventsChanged(added);
640 }
Alex Light0aa7a5a2018-10-10 15:58:14 +0000641 if (caps.can_pop_frame == 1 && added) {
642 // TODO We should keep track of how many of these have been enabled and remove it if there are
643 // no more possible users. This isn't expected to be too common.
644 art::Runtime::Current()->SetNonStandardExitsEnabled();
645 }
Alex Light73afd322017-01-18 11:17:47 -0800646 }
647}
648
Andreas Gampe77708d92016-10-07 11:48:21 -0700649} // namespace openjdkjvmti
650
Andreas Gampe06c42a52017-07-26 14:17:14 -0700651#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_