blob: 92cfbc9c417240f52486e3ae8c66862f8306eb7d [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"
David Srbecky28f6cff2018-10-16 15:07:28 +010028#include "runtime-inl.h"
Alex Light9df79b72017-09-12 08:57:31 -070029#include "scoped_thread_state_change-inl.h"
Alex Light0aa7a5a2018-10-10 15:58:14 +000030#include "stack.h"
Alex Lighta26e3492017-06-27 17:55:37 -070031#include "ti_breakpoint.h"
Alex Light0aa7a5a2018-10-10 15:58:14 +000032#include "ti_thread.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070033
34#include "art_jvmti.h"
35
36namespace openjdkjvmti {
37
Alex Light73afd322017-01-18 11:17:47 -080038static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
39 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
40 if (env->capabilities.can_retransform_classes) {
41 return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
42 } else {
43 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
44 }
45 } else {
46 return static_cast<ArtJvmtiEvent>(e);
47 }
Alex Light40d87f42017-01-18 10:27:06 -080048}
49
Andreas Gampe983c1752017-01-23 19:46:56 -080050namespace impl {
Andreas Gampe77708d92016-10-07 11:48:21 -070051
Orion Hodsonaacf9772020-07-22 21:51:00 +010052// Helper for ensuring that the dispatch environment is suitably provisioned. Events with JNIEnvs
53// need to stash pending exceptions since they can cause new ones to be thrown. In accordance with
54// the JVMTI specification we allow exceptions originating from events to overwrite the current
55// exception, including exceptions originating from earlier events.
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010056class ScopedEventDispatchEnvironment final : public art::ValueObject {
Alex Lightb284f8d2017-11-21 00:00:48 +000057 public:
58 ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
59 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
60 }
61
62 explicit ScopedEventDispatchEnvironment(JNIEnv* env)
63 : env_(env),
64 throw_(env_, env_->ExceptionOccurred()) {
65 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
66 // The spec doesn't say how much local data should be there, so we just give 128 which seems
67 // likely to be enough for most cases.
68 env_->PushLocalFrame(128);
69 env_->ExceptionClear();
70 }
71
72 ~ScopedEventDispatchEnvironment() {
73 if (env_ != nullptr) {
74 if (throw_.get() != nullptr && !env_->ExceptionCheck()) {
75 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list
76 // of the newest exception.
77 env_->Throw(throw_.get());
78 }
79 env_->PopLocalFrame(nullptr);
80 }
81 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
82 }
83
84 private:
85 JNIEnv* env_;
86 ScopedLocalRef<jthrowable> throw_;
87
88 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment);
89};
90
Andreas Gampe983c1752017-01-23 19:46:56 -080091// Infrastructure to achieve type safety for event dispatch.
Andreas Gampe27fa96c2016-10-07 15:05:24 -070092
Alex Lightd55b8442019-10-15 15:46:07 -070093#define FORALL_EVENT_TYPES(fn) \
94 fn(VMInit, ArtJvmtiEvent::kVmInit) \
95 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
96 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
97 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
98 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
99 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
100 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
101 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
102 fn(VMStart, ArtJvmtiEvent::kVmStart) \
103 fn(Exception, ArtJvmtiEvent::kException) \
104 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
105 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
106 fn(FramePop, ArtJvmtiEvent::kFramePop) \
107 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
108 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
109 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
110 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
111 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
112 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
113 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
114 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
115 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
116 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
117 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
118 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
119 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
120 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
121 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
122 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
123 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
124 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
125 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc) \
126 fn(DdmPublishChunk, ArtJvmtiEvent::kDdmPublishChunk) \
127 fn(ObsoleteObjectCreated, ArtJvmtiEvent::kObsoleteObjectCreated) \
128 fn(StructuralDexFileLoadHook, ArtJvmtiEvent::kStructuralDexFileLoadHook)
Andreas Gampe983c1752017-01-23 19:46:56 -0800129
130template <ArtJvmtiEvent kEvent>
131struct EventFnType {
132};
133
Alex Light8c2b9292017-11-09 13:21:01 -0800134#define EVENT_FN_TYPE(name, enum_name) \
135template <> \
136struct EventFnType<enum_name> { \
137 using type = decltype(ArtJvmtiEventCallbacks().name); \
Andreas Gampe983c1752017-01-23 19:46:56 -0800138};
139
140FORALL_EVENT_TYPES(EVENT_FN_TYPE)
141
142#undef EVENT_FN_TYPE
143
Alex Lightb284f8d2017-11-21 00:00:48 +0000144#define MAKE_EVENT_HANDLER_FUNC(name, enum_name) \
145template<> \
146struct EventHandlerFunc<enum_name> { \
147 using EventFnType = typename impl::EventFnType<enum_name>::type; \
148 explicit EventHandlerFunc(ArtJvmTiEnv* env) \
149 : env_(env), \
150 fn_(env_->event_callbacks == nullptr ? nullptr : env_->event_callbacks->name) { } \
151 \
152 template <typename ...Args> \
153 ALWAYS_INLINE \
154 void ExecuteCallback(JNIEnv* jnienv, Args... args) const { \
155 if (fn_ != nullptr) { \
156 ScopedEventDispatchEnvironment sede(jnienv); \
157 DoExecute(jnienv, args...); \
158 } \
159 } \
160 \
161 template <typename ...Args> \
162 ALWAYS_INLINE \
163 void ExecuteCallback(Args... args) const { \
164 if (fn_ != nullptr) { \
165 ScopedEventDispatchEnvironment sede; \
166 DoExecute(args...); \
167 } \
168 } \
169 \
170 private: \
171 template <typename ...Args> \
172 ALWAYS_INLINE \
173 inline void DoExecute(Args... args) const { \
174 static_assert(std::is_same<EventFnType, void(*)(jvmtiEnv*, Args...)>::value, \
175 "Unexpected different type of ExecuteCallback"); \
176 fn_(env_, args...); \
177 } \
178 \
179 public: \
180 ArtJvmTiEnv* env_; \
181 EventFnType fn_; \
182};
Andreas Gampe983c1752017-01-23 19:46:56 -0800183
Alex Lightb284f8d2017-11-21 00:00:48 +0000184FORALL_EVENT_TYPES(MAKE_EVENT_HANDLER_FUNC)
Andreas Gampe77708d92016-10-07 11:48:21 -0700185
Alex Lightb284f8d2017-11-21 00:00:48 +0000186#undef MAKE_EVENT_HANDLER_FUNC
Andreas Gampe983c1752017-01-23 19:46:56 -0800187
188#undef FORALL_EVENT_TYPES
189
190} // namespace impl
191
Alex Lightb284f8d2017-11-21 00:00:48 +0000192template <ArtJvmtiEvent kEvent, typename ...Args>
193inline std::vector<impl::EventHandlerFunc<kEvent>> EventHandler::CollectEvents(art::Thread* thread,
194 Args... args) const {
Alex Light2a96fe82018-01-22 17:45:02 -0800195 art::ReaderMutexLock mu(thread, envs_lock_);
Alex Lightb284f8d2017-11-21 00:00:48 +0000196 std::vector<impl::EventHandlerFunc<kEvent>> handlers;
197 for (ArtJvmTiEnv* env : envs) {
198 if (ShouldDispatch<kEvent>(env, thread, args...)) {
199 impl::EventHandlerFunc<kEvent> h(env);
200 handlers.push_back(h);
201 }
202 }
203 return handlers;
204}
205
Andreas Gampe983c1752017-01-23 19:46:56 -0800206// C++ does not allow partial template function specialization. The dispatch for our separated
207// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
Andreas Gampe983c1752017-01-23 19:46:56 -0800208template <ArtJvmtiEvent kEvent>
Alex Light6ac57502017-01-19 15:05:06 -0800209inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
Alex Light6ac57502017-01-19 15:05:06 -0800210 JNIEnv* jnienv,
211 jclass class_being_redefined,
212 jobject loader,
213 const char* name,
214 jobject protection_domain,
215 jint class_data_len,
216 const unsigned char* class_data,
217 jint* new_class_data_len,
218 unsigned char** new_class_data) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000219 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
Andreas Gampe983c1752017-01-23 19:46:56 -0800220 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
Alex Lightd55b8442019-10-15 15:46:07 -0700221 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
222 kEvent == ArtJvmtiEvent::kStructuralDexFileLoadHook, "Unsupported event");
Alex Light51271782017-03-24 17:28:30 -0700223 DCHECK(*new_class_data == nullptr);
Alex Light6ac57502017-01-19 15:05:06 -0800224 jint current_len = class_data_len;
225 unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
Alex Lightb284f8d2017-11-21 00:00:48 +0000226 std::vector<impl::EventHandlerFunc<kEvent>> handlers =
227 CollectEvents<kEvent>(thread,
228 jnienv,
229 class_being_redefined,
230 loader,
231 name,
232 protection_domain,
233 class_data_len,
234 class_data,
235 new_class_data_len,
236 new_class_data);
Alex Light6ac57502017-01-19 15:05:06 -0800237 ArtJvmTiEnv* last_env = nullptr;
Alex Lightb284f8d2017-11-21 00:00:48 +0000238 for (const impl::EventHandlerFunc<kEvent>& event : handlers) {
Alex Light9df79b72017-09-12 08:57:31 -0700239 jint new_len = 0;
240 unsigned char* new_data = nullptr;
Alex Lightb284f8d2017-11-21 00:00:48 +0000241 ExecuteCallback<kEvent>(event,
242 jnienv,
243 class_being_redefined,
244 loader,
245 name,
246 protection_domain,
247 current_len,
248 static_cast<const unsigned char*>(current_class_data),
249 &new_len,
250 &new_data);
Alex Light9df79b72017-09-12 08:57:31 -0700251 if (new_data != nullptr && new_data != current_class_data) {
252 // Destroy the data the last transformer made. We skip this if the previous state was the
253 // initial one since we don't know here which jvmtiEnv allocated it.
254 // NB Currently this doesn't matter since all allocations just go to malloc but in the
255 // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
256 if (last_env != nullptr) {
257 last_env->Deallocate(current_class_data);
Alex Lightb7edcda2017-04-27 13:20:31 -0700258 }
Alex Lightb284f8d2017-11-21 00:00:48 +0000259 last_env = event.env_;
Alex Light9df79b72017-09-12 08:57:31 -0700260 current_class_data = new_data;
261 current_len = new_len;
Alex Light6ac57502017-01-19 15:05:06 -0800262 }
263 }
264 if (last_env != nullptr) {
265 *new_class_data_len = current_len;
266 *new_class_data = current_class_data;
267 }
268}
269
Andreas Gampe983c1752017-01-23 19:46:56 -0800270// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
271// exactly the argument types of the corresponding Jvmti kEvent function pointer.
Alex Light6ac57502017-01-19 15:05:06 -0800272
Andreas Gampe983c1752017-01-23 19:46:56 -0800273template <ArtJvmtiEvent kEvent, typename ...Args>
Andreas Gampea1705ea2017-03-28 20:12:13 -0700274inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000275 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
Alex Light9df79b72017-09-12 08:57:31 -0700276 static_assert(!std::is_same<JNIEnv*,
277 typename std::decay_t<
278 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
279 "Should be calling DispatchEvent with explicit JNIEnv* argument!");
280 DCHECK(thread == nullptr || !thread->IsExceptionPending());
Alex Lightb284f8d2017-11-21 00:00:48 +0000281 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, args...);
282 for (auto event : events) {
283 ExecuteCallback<kEvent>(event, args...);
Andreas Gampea1705ea2017-03-28 20:12:13 -0700284 }
285}
286
Alex Lightb7edcda2017-04-27 13:20:31 -0700287template <ArtJvmtiEvent kEvent, typename ...Args>
288inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000289 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
290 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
291 jnienv,
292 args...);
293 for (auto event : events) {
294 ExecuteCallback<kEvent>(event, jnienv, args...);
Alex Lightb7edcda2017-04-27 13:20:31 -0700295 }
296}
297
Andreas Gampea1705ea2017-03-28 20:12:13 -0700298template <ArtJvmtiEvent kEvent, typename ...Args>
Alex Light9df79b72017-09-12 08:57:31 -0700299inline void EventHandler::DispatchEventOnEnv(
300 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const {
301 DCHECK(env != nullptr);
302 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) {
Alex Lightb284f8d2017-11-21 00:00:48 +0000303 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
304 impl::EventHandlerFunc<kEvent> func(env);
305 ExecuteCallback<kEvent>(func, jnienv, args...);
Andreas Gampe77708d92016-10-07 11:48:21 -0700306 }
307}
308
Alex Light9df79b72017-09-12 08:57:31 -0700309template <ArtJvmtiEvent kEvent, typename ...Args>
310inline void EventHandler::DispatchEventOnEnv(
311 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
312 static_assert(!std::is_same<JNIEnv*,
313 typename std::decay_t<
314 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value,
315 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!");
Alex Lightb284f8d2017-11-21 00:00:48 +0000316 DCHECK(env != nullptr);
317 if (ShouldDispatch<kEvent, Args...>(env, thread, args...)) {
318 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
319 impl::EventHandlerFunc<kEvent> func(env);
320 ExecuteCallback<kEvent>(func, args...);
Alex Light9df79b72017-09-12 08:57:31 -0700321 }
322}
323
Alex Light72d7e942019-07-23 13:10:20 -0700324template <>
325inline void EventHandler::DispatchEventOnEnv<ArtJvmtiEvent::kObsoleteObjectCreated>(
326 ArtJvmTiEnv* env, art::Thread* thread, jlong* obsolete_tag, jlong* new_tag) const {
327 static constexpr ArtJvmtiEvent kEvent = ArtJvmtiEvent::kObsoleteObjectCreated;
328 DCHECK(env != nullptr);
329 if (ShouldDispatch<kEvent>(env, thread, obsolete_tag, new_tag)) {
330 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
331 impl::EventHandlerFunc<kEvent> func(env);
332 ExecuteCallback<kEvent>(func, obsolete_tag, new_tag);
333 } else {
334 // Unlike most others this has a default action to make sure that agents without knowledge of
335 // this extension get reasonable behavior.
336 jlong temp = *obsolete_tag;
337 *obsolete_tag = *new_tag;
338 *new_tag = temp;
339 }
340}
341
Alex Lightb284f8d2017-11-21 00:00:48 +0000342template <ArtJvmtiEvent kEvent, typename ...Args>
343inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) {
344 handler.ExecuteCallback(args...);
345}
346
347template <ArtJvmtiEvent kEvent, typename ...Args>
348inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
349 JNIEnv* jnienv,
350 Args... args) {
351 handler.ExecuteCallback(jnienv, args...);
352}
353
Alex Light9df79b72017-09-12 08:57:31 -0700354// Events that need custom logic for if we send the event but are otherwise normal. This includes
355// the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
356
Alex Lighta26e3492017-06-27 17:55:37 -0700357// Need to give custom specializations for Breakpoint since it needs to filter out which particular
358// methods/dex_pcs agents get notified on.
359template <>
Alex Light9df79b72017-09-12 08:57:31 -0700360inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
361 ArtJvmTiEnv* env,
362 art::Thread* thread,
363 JNIEnv* jnienv ATTRIBUTE_UNUSED,
364 jthread jni_thread ATTRIBUTE_UNUSED,
365 jmethodID jmethod,
366 jlocation location) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700367 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Lighta26e3492017-06-27 17:55:37 -0700368 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
Alex Light9df79b72017-09-12 08:57:31 -0700369 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
370 env->breakpoints.find({method, location}) != env->breakpoints.end();
Alex Lighta26e3492017-06-27 17:55:37 -0700371}
372
Alex Lighte814f9d2017-07-31 16:14:39 -0700373template <>
Alex Light9df79b72017-09-12 08:57:31 -0700374inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
375 ArtJvmTiEnv* env,
Alex Lighte814f9d2017-07-31 16:14:39 -0700376 art::Thread* thread,
Alex Light9df79b72017-09-12 08:57:31 -0700377 JNIEnv* jnienv ATTRIBUTE_UNUSED,
378 jthread jni_thread ATTRIBUTE_UNUSED,
379 jmethodID jmethod ATTRIBUTE_UNUSED,
380 jboolean is_exception ATTRIBUTE_UNUSED,
Alex Lighte814f9d2017-07-31 16:14:39 -0700381 const art::ShadowFrame* frame) const {
Alex Light9df79b72017-09-12 08:57:31 -0700382 // Search for the frame. Do this before checking if we need to send the event so that we don't
383 // have to deal with use-after-free or the frames being reallocated later.
Alex Lightb6106d52017-10-18 15:02:15 -0700384 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700385 return env->notify_frames.erase(frame) != 0 &&
Alex Lightb7c640d2019-03-20 15:52:13 -0700386 !frame->GetSkipMethodExitEvents() &&
Alex Light9df79b72017-09-12 08:57:31 -0700387 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
Alex Lighte814f9d2017-07-31 16:14:39 -0700388}
389
Alex Light084fa372017-06-16 08:58:34 -0700390// Need to give custom specializations for FieldAccess and FieldModification since they need to
391// filter out which particular fields agents want to get notified on.
392// TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
393// could make the system more performant.
394template <>
Alex Light9df79b72017-09-12 08:57:31 -0700395inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
396 ArtJvmTiEnv* env,
397 art::Thread* thread,
398 JNIEnv* jnienv ATTRIBUTE_UNUSED,
399 jthread jni_thread ATTRIBUTE_UNUSED,
400 jmethodID method ATTRIBUTE_UNUSED,
401 jlocation location ATTRIBUTE_UNUSED,
402 jclass field_klass ATTRIBUTE_UNUSED,
403 jobject object ATTRIBUTE_UNUSED,
404 jfieldID field,
405 char type_char ATTRIBUTE_UNUSED,
406 jvalue val ATTRIBUTE_UNUSED) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700407 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700408 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
409 env->modify_watched_fields.find(
410 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
Alex Light084fa372017-06-16 08:58:34 -0700411}
412
413template <>
Alex Light9df79b72017-09-12 08:57:31 -0700414inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
415 ArtJvmTiEnv* env,
416 art::Thread* thread,
417 JNIEnv* jnienv ATTRIBUTE_UNUSED,
418 jthread jni_thread ATTRIBUTE_UNUSED,
419 jmethodID method ATTRIBUTE_UNUSED,
420 jlocation location ATTRIBUTE_UNUSED,
421 jclass field_klass ATTRIBUTE_UNUSED,
422 jobject object ATTRIBUTE_UNUSED,
423 jfieldID field) const {
Alex Lightb6106d52017-10-18 15:02:15 -0700424 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
Alex Light9df79b72017-09-12 08:57:31 -0700425 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
426 env->access_watched_fields.find(
427 art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
428}
429
430// Need to give custom specializations for FramePop since it needs to filter out which particular
431// agents get the event. This specialization gets an extra argument so we can determine which (if
432// any) environments have the frame pop.
433// TODO It might be useful to use more template magic to have this only define ShouldDispatch or
434// something.
435template <>
436inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
Alex Lightb284f8d2017-11-21 00:00:48 +0000437 impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
Alex Light9df79b72017-09-12 08:57:31 -0700438 JNIEnv* jnienv,
439 jthread jni_thread,
440 jmethodID jmethod,
441 jboolean is_exception,
442 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) {
Alex Lightb284f8d2017-11-21 00:00:48 +0000443 ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
Alex Light084fa372017-06-16 08:58:34 -0700444}
445
Alex Light0aa7a5a2018-10-10 15:58:14 +0000446struct ScopedDisablePopFrame {
447 public:
448 explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) {
449 art::Locks::mutator_lock_->AssertSharedHeld(thread_);
450 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
451 JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_);
452 current_top_frame_ = art::StackVisitor::ComputeNumFrames(
453 thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
454 old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
455 data->disable_pop_frame_depth = current_top_frame_;
Alex Lightb2e6d0f2019-12-12 17:15:23 -0800456 // Check that we cleaned up any old disables. This should only increase (or be equals if we do
457 // another ClassLoad/Prepare recursively).
Alex Light0aa7a5a2018-10-10 15:58:14 +0000458 DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
Alex Lightb2e6d0f2019-12-12 17:15:23 -0800459 current_top_frame_ >= old_disable_frame_pop_depth_)
Alex Light0aa7a5a2018-10-10 15:58:14 +0000460 << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
461 }
462
463 ~ScopedDisablePopFrame() {
464 art::Locks::mutator_lock_->AssertSharedHeld(thread_);
465 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
466 JvmtiGlobalTLSData* data = ThreadUtil::GetGlobalTLSData(thread_);
467 DCHECK_EQ(data->disable_pop_frame_depth, current_top_frame_);
468 data->disable_pop_frame_depth = old_disable_frame_pop_depth_;
469 }
470
471 private:
472 art::Thread* thread_;
473 size_t current_top_frame_;
474 size_t old_disable_frame_pop_depth_;
475};
476// We want to prevent the use of PopFrame when reporting either of these events.
477template <ArtJvmtiEvent kEvent>
478inline void EventHandler::DispatchClassLoadOrPrepareEvent(art::Thread* thread,
479 JNIEnv* jnienv,
480 jthread jni_thread,
481 jclass klass) const {
482 ScopedDisablePopFrame sdpf(thread);
483 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
484 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
485 jnienv,
486 jni_thread,
487 klass);
488
489 for (auto event : events) {
490 ExecuteCallback<kEvent>(event, jnienv, jni_thread, klass);
491 }
492}
493
494template <>
495inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassLoad>(art::Thread* thread,
496 JNIEnv* jnienv,
497 jthread jni_thread,
498 jclass klass) const {
499 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassLoad>(thread, jnienv, jni_thread, klass);
500}
501template <>
502inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassPrepare>(art::Thread* thread,
503 JNIEnv* jnienv,
504 jthread jni_thread,
505 jclass klass) const {
506 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassPrepare>(thread, jnienv, jni_thread, klass);
507}
508
Alex Lightd78ddec2017-04-18 15:20:38 -0700509// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
510// variable.
511template <>
512inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
513 JNIEnv* jnienv,
514 jthread jni_thread,
515 jmethodID method,
516 void* cur_method,
517 void** new_method) const {
Alex Lightb284f8d2017-11-21 00:00:48 +0000518 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
519 std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
520 CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
521 jnienv,
522 jni_thread,
523 method,
524 cur_method,
525 new_method);
Alex Lightd78ddec2017-04-18 15:20:38 -0700526 *new_method = cur_method;
Alex Lightb284f8d2017-11-21 00:00:48 +0000527 for (auto event : events) {
528 *new_method = cur_method;
529 ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
530 jnienv,
531 jni_thread,
532 method,
533 cur_method,
534 new_method);
535 if (*new_method != nullptr) {
536 cur_method = *new_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700537 }
538 }
Alex Light9df79b72017-09-12 08:57:31 -0700539 *new_method = cur_method;
Alex Lightd78ddec2017-04-18 15:20:38 -0700540}
541
Andreas Gampe983c1752017-01-23 19:46:56 -0800542// C++ does not allow partial template function specialization. The dispatch for our separated
543// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
544// The following two DispatchEvent specializations dispatch to it.
545template <>
546inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
547 art::Thread* thread,
548 JNIEnv* jnienv,
549 jclass class_being_redefined,
550 jobject loader,
551 const char* name,
552 jobject protection_domain,
553 jint class_data_len,
554 const unsigned char* class_data,
555 jint* new_class_data_len,
556 unsigned char** new_class_data) const {
557 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
558 thread,
559 jnienv,
560 class_being_redefined,
561 loader,
562 name,
563 protection_domain,
564 class_data_len,
565 class_data,
566 new_class_data_len,
567 new_class_data);
568}
Alex Light9df79b72017-09-12 08:57:31 -0700569
Andreas Gampe983c1752017-01-23 19:46:56 -0800570template <>
571inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
572 art::Thread* thread,
573 JNIEnv* jnienv,
574 jclass class_being_redefined,
575 jobject loader,
576 const char* name,
577 jobject protection_domain,
578 jint class_data_len,
579 const unsigned char* class_data,
580 jint* new_class_data_len,
581 unsigned char** new_class_data) const {
582 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
583 thread,
584 jnienv,
585 class_being_redefined,
586 loader,
587 name,
588 protection_domain,
589 class_data_len,
590 class_data,
591 new_class_data_len,
592 new_class_data);
593}
Alex Light40d87f42017-01-18 10:27:06 -0800594
Alex Lightd55b8442019-10-15 15:46:07 -0700595template <>
596inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
597 art::Thread* thread,
598 JNIEnv* jnienv,
599 jclass class_being_redefined,
600 jobject loader,
601 const char* name,
602 jobject protection_domain,
603 jint class_data_len,
604 const unsigned char* class_data,
605 jint* new_class_data_len,
606 unsigned char** new_class_data) const {
607 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
608 thread,
609 jnienv,
610 class_being_redefined,
611 loader,
612 name,
613 protection_domain,
614 class_data_len,
615 class_data,
616 new_class_data_len,
617 new_class_data);
618}
619
Andreas Gampe983c1752017-01-23 19:46:56 -0800620template <ArtJvmtiEvent kEvent>
Alex Lightb284f8d2017-11-21 00:00:48 +0000621inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const {
Andreas Gampe983c1752017-01-23 19:46:56 -0800622 bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
623
624 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
Alex Light40d87f42017-01-18 10:27:06 -0800625 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
Andreas Gampe983c1752017-01-23 19:46:56 -0800626 dispatch = mask != nullptr && mask->Test(kEvent);
Alex Light40d87f42017-01-18 10:27:06 -0800627 }
628 return dispatch;
629}
630
Alex Light9df79b72017-09-12 08:57:31 -0700631template <ArtJvmtiEvent kEvent, typename ...Args>
632inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
633 art::Thread* thread,
634 Args... args ATTRIBUTE_UNUSED) const {
635 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type,
636 void(*)(jvmtiEnv*, Args...)>::value,
637 "Unexpected different type of shouldDispatch");
638
639 return ShouldDispatchOnThread<kEvent>(env, thread);
640}
641
Alex Light73afd322017-01-18 11:17:47 -0800642inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
Alex Light2a96fe82018-01-22 17:45:02 -0800643 art::WriterMutexLock mu(art::Thread::Current(), envs_lock_);
Alex Lightb284f8d2017-11-21 00:00:48 +0000644 RecalculateGlobalEventMaskLocked(event);
645}
646
647inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) {
Alex Light73afd322017-01-18 11:17:47 -0800648 bool union_value = false;
649 for (const ArtJvmTiEnv* stored_env : envs) {
Alex Lightbb766462017-04-12 16:13:33 -0700650 if (stored_env == nullptr) {
651 continue;
652 }
Alex Light73afd322017-01-18 11:17:47 -0800653 union_value |= stored_env->event_masks.global_event_mask.Test(event);
654 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
655 if (union_value) {
656 break;
657 }
658 }
659 global_mask.Set(event, union_value);
660}
661
662inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
663 const jvmtiCapabilities& caps,
664 bool added) {
665 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
666 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700667 return (added && caps.can_access_local_variables == 1) ||
Alex Light0fa17862017-10-24 13:43:05 -0700668 caps.can_generate_breakpoint_events == 1 ||
Alex Light0aa7a5a2018-10-10 15:58:14 +0000669 caps.can_pop_frame == 1 ||
Alex Lightb7c640d2019-03-20 15:52:13 -0700670 caps.can_force_early_return == 1 ||
Alex Lightbebd7bd2017-07-25 14:05:52 -0700671 (caps.can_retransform_classes == 1 &&
672 IsEventEnabledAnywhere(event) &&
673 env->event_masks.IsEnabledAnywhere(event));
Alex Light73afd322017-01-18 11:17:47 -0800674}
675
676inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
677 const jvmtiCapabilities& caps,
678 bool added) {
679 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
680 env->event_masks.HandleChangedCapabilities(caps, added);
681 if (caps.can_retransform_classes == 1) {
682 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
683 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
684 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700685 if (added && caps.can_access_local_variables == 1) {
686 HandleLocalAccessCapabilityAdded();
687 }
Alex Light0fa17862017-10-24 13:43:05 -0700688 if (caps.can_generate_breakpoint_events == 1) {
689 HandleBreakpointEventsChanged(added);
690 }
Alex Lightb7c640d2019-03-20 15:52:13 -0700691 if ((caps.can_pop_frame == 1 || caps.can_force_early_return == 1) && added) {
Alex Light0aa7a5a2018-10-10 15:58:14 +0000692 // TODO We should keep track of how many of these have been enabled and remove it if there are
693 // no more possible users. This isn't expected to be too common.
694 art::Runtime::Current()->SetNonStandardExitsEnabled();
695 }
Alex Light73afd322017-01-18 11:17:47 -0800696 }
697}
698
Andreas Gampe77708d92016-10-07 11:48:21 -0700699} // namespace openjdkjvmti
700
Andreas Gampe06c42a52017-07-26 14:17:14 -0700701#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_