ART: Refactor TI events
Refactor for type safety of event dispatch. Use template specialization
to ensure that only correct calls will work.
Bug: 31684920
Test: m test-art-host
Change-Id: Ifbb47447fb46dd6e799bc824a60df51b15b73618
diff --git a/runtime/openjdkjvmti/events-inl.h b/runtime/openjdkjvmti/events-inl.h
index 21ec731..655a53a 100644
--- a/runtime/openjdkjvmti/events-inl.h
+++ b/runtime/openjdkjvmti/events-inl.h
@@ -37,96 +37,84 @@
}
}
-template <typename FnType>
-ALWAYS_INLINE static inline FnType* GetCallback(ArtJvmTiEnv* env, ArtJvmtiEvent event) {
- if (env->event_callbacks == nullptr) {
- return nullptr;
- }
+namespace impl {
- // TODO: Add a type check. Can be done, for example, by an explicitly instantiated template
- // function.
+// Infrastructure to achieve type safety for event dispatch.
- switch (event) {
- case ArtJvmtiEvent::kVmInit:
- return reinterpret_cast<FnType*>(env->event_callbacks->VMInit);
- case ArtJvmtiEvent::kVmDeath:
- return reinterpret_cast<FnType*>(env->event_callbacks->VMDeath);
- case ArtJvmtiEvent::kThreadStart:
- return reinterpret_cast<FnType*>(env->event_callbacks->ThreadStart);
- case ArtJvmtiEvent::kThreadEnd:
- return reinterpret_cast<FnType*>(env->event_callbacks->ThreadEnd);
- case ArtJvmtiEvent::kClassFileLoadHookRetransformable:
- case ArtJvmtiEvent::kClassFileLoadHookNonRetransformable:
- return reinterpret_cast<FnType*>(env->event_callbacks->ClassFileLoadHook);
- case ArtJvmtiEvent::kClassLoad:
- return reinterpret_cast<FnType*>(env->event_callbacks->ClassLoad);
- case ArtJvmtiEvent::kClassPrepare:
- return reinterpret_cast<FnType*>(env->event_callbacks->ClassPrepare);
- case ArtJvmtiEvent::kVmStart:
- return reinterpret_cast<FnType*>(env->event_callbacks->VMStart);
- case ArtJvmtiEvent::kException:
- return reinterpret_cast<FnType*>(env->event_callbacks->Exception);
- case ArtJvmtiEvent::kExceptionCatch:
- return reinterpret_cast<FnType*>(env->event_callbacks->ExceptionCatch);
- case ArtJvmtiEvent::kSingleStep:
- return reinterpret_cast<FnType*>(env->event_callbacks->SingleStep);
- case ArtJvmtiEvent::kFramePop:
- return reinterpret_cast<FnType*>(env->event_callbacks->FramePop);
- case ArtJvmtiEvent::kBreakpoint:
- return reinterpret_cast<FnType*>(env->event_callbacks->Breakpoint);
- case ArtJvmtiEvent::kFieldAccess:
- return reinterpret_cast<FnType*>(env->event_callbacks->FieldAccess);
- case ArtJvmtiEvent::kFieldModification:
- return reinterpret_cast<FnType*>(env->event_callbacks->FieldModification);
- case ArtJvmtiEvent::kMethodEntry:
- return reinterpret_cast<FnType*>(env->event_callbacks->MethodEntry);
- case ArtJvmtiEvent::kMethodExit:
- return reinterpret_cast<FnType*>(env->event_callbacks->MethodExit);
- case ArtJvmtiEvent::kNativeMethodBind:
- return reinterpret_cast<FnType*>(env->event_callbacks->NativeMethodBind);
- case ArtJvmtiEvent::kCompiledMethodLoad:
- return reinterpret_cast<FnType*>(env->event_callbacks->CompiledMethodLoad);
- case ArtJvmtiEvent::kCompiledMethodUnload:
- return reinterpret_cast<FnType*>(env->event_callbacks->CompiledMethodUnload);
- case ArtJvmtiEvent::kDynamicCodeGenerated:
- return reinterpret_cast<FnType*>(env->event_callbacks->DynamicCodeGenerated);
- case ArtJvmtiEvent::kDataDumpRequest:
- return reinterpret_cast<FnType*>(env->event_callbacks->DataDumpRequest);
- case ArtJvmtiEvent::kMonitorWait:
- return reinterpret_cast<FnType*>(env->event_callbacks->MonitorWait);
- case ArtJvmtiEvent::kMonitorWaited:
- return reinterpret_cast<FnType*>(env->event_callbacks->MonitorWaited);
- case ArtJvmtiEvent::kMonitorContendedEnter:
- return reinterpret_cast<FnType*>(env->event_callbacks->MonitorContendedEnter);
- case ArtJvmtiEvent::kMonitorContendedEntered:
- return reinterpret_cast<FnType*>(env->event_callbacks->MonitorContendedEntered);
- case ArtJvmtiEvent::kResourceExhausted:
- return reinterpret_cast<FnType*>(env->event_callbacks->ResourceExhausted);
- case ArtJvmtiEvent::kGarbageCollectionStart:
- return reinterpret_cast<FnType*>(env->event_callbacks->GarbageCollectionStart);
- case ArtJvmtiEvent::kGarbageCollectionFinish:
- return reinterpret_cast<FnType*>(env->event_callbacks->GarbageCollectionFinish);
- case ArtJvmtiEvent::kObjectFree:
- return reinterpret_cast<FnType*>(env->event_callbacks->ObjectFree);
- case ArtJvmtiEvent::kVmObjectAlloc:
- return reinterpret_cast<FnType*>(env->event_callbacks->VMObjectAlloc);
- }
- return nullptr;
+#define FORALL_EVENT_TYPES(fn) \
+ fn(VMInit, ArtJvmtiEvent::kVmInit) \
+ fn(VMDeath, ArtJvmtiEvent::kVmDeath) \
+ fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \
+ fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \
+ fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \
+ fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \
+ fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \
+ fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \
+ fn(VMStart, ArtJvmtiEvent::kVmStart) \
+ fn(Exception, ArtJvmtiEvent::kException) \
+ fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \
+ fn(SingleStep, ArtJvmtiEvent::kSingleStep) \
+ fn(FramePop, ArtJvmtiEvent::kFramePop) \
+ fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \
+ fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \
+ fn(FieldModification, ArtJvmtiEvent::kFieldModification) \
+ fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \
+ fn(MethodExit, ArtJvmtiEvent::kMethodExit) \
+ fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \
+ fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \
+ fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \
+ fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \
+ fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \
+ fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \
+ fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \
+ fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \
+ fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \
+ fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \
+ fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
+ fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
+ fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
+ fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc)
+
+template <ArtJvmtiEvent kEvent>
+struct EventFnType {
+};
+
+#define EVENT_FN_TYPE(name, enum_name) \
+template <> \
+struct EventFnType<enum_name> { \
+ using type = decltype(jvmtiEventCallbacks().name); \
+};
+
+FORALL_EVENT_TYPES(EVENT_FN_TYPE)
+
+#undef EVENT_FN_TYPE
+
+template <ArtJvmtiEvent kEvent>
+ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
+
+#define GET_CALLBACK(name, enum_name) \
+template <> \
+ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
+ ArtJvmTiEnv* env) { \
+ if (env->event_callbacks == nullptr) { \
+ return nullptr; \
+ } \
+ return env->event_callbacks->name; \
}
-template <typename ...Args>
-inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread*,
- ArtJvmtiEvent event,
- Args... args ATTRIBUTE_UNUSED) const {
- CHECK(event == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
- event == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
- LOG(FATAL) << "Incorrect arguments to ClassFileLoadHook!";
-}
+FORALL_EVENT_TYPES(GET_CALLBACK)
+#undef GET_CALLBACK
+
+#undef FORALL_EVENT_TYPES
+
+} // namespace impl
+
+// C++ does not allow partial template function specialization. The dispatch for our separated
+// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
// TODO Locking of some type!
-template <>
+template <ArtJvmtiEvent kEvent>
inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
- ArtJvmtiEvent event,
JNIEnv* jnienv,
jclass class_being_redefined,
jobject loader,
@@ -136,26 +124,16 @@
const unsigned char* class_data,
jint* new_class_data_len,
unsigned char** new_class_data) const {
- CHECK(event == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
- event == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
- using FnType = void(jvmtiEnv* /* jvmti_env */,
- JNIEnv* /* jnienv */,
- jclass /* class_being_redefined */,
- jobject /* loader */,
- const char* /* name */,
- jobject /* protection_domain */,
- jint /* class_data_len */,
- const unsigned char* /* class_data */,
- jint* /* new_class_data_len */,
- unsigned char** /* new_class_data */);
+ static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
+ kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
jint current_len = class_data_len;
unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
ArtJvmTiEnv* last_env = nullptr;
for (ArtJvmTiEnv* env : envs) {
- if (ShouldDispatch(event, env, thread)) {
+ if (ShouldDispatch<kEvent>(env, thread)) {
jint new_len;
unsigned char* new_data;
- FnType* callback = GetCallback<FnType>(env, event);
+ auto callback = impl::GetCallback<kEvent>(env);
callback(env,
jnienv,
class_being_redefined,
@@ -186,28 +164,16 @@
}
}
-template <typename ...Args>
-inline void EventHandler::DispatchEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const {
- switch (event) {
- case ArtJvmtiEvent::kClassFileLoadHookRetransformable:
- case ArtJvmtiEvent::kClassFileLoadHookNonRetransformable:
- return DispatchClassFileLoadHookEvent(thread, event, args...);
- default:
- return GenericDispatchEvent(thread, event, args...);
- }
-}
+// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
+// exactly the argument types of the corresponding Jvmti kEvent function pointer.
-// TODO Locking of some type!
-template <typename ...Args>
-inline void EventHandler::GenericDispatchEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const {
+template <ArtJvmtiEvent kEvent, typename ...Args>
+inline void EventHandler::DispatchEvent(art::Thread* thread,
+ Args... args) const {
using FnType = void(jvmtiEnv*, Args...);
for (ArtJvmTiEnv* env : envs) {
- if (ShouldDispatch(event, env, thread)) {
- FnType* callback = GetCallback<FnType>(env, event);
+ if (ShouldDispatch<kEvent>(env, thread)) {
+ FnType* callback = impl::GetCallback<kEvent>(env);
if (callback != nullptr) {
(*callback)(env, args...);
}
@@ -215,14 +181,66 @@
}
}
-inline bool EventHandler::ShouldDispatch(ArtJvmtiEvent event,
- ArtJvmTiEnv* env,
- art::Thread* thread) {
- bool dispatch = env->event_masks.global_event_mask.Test(event);
+// C++ does not allow partial template function specialization. The dispatch for our separated
+// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
+// The following two DispatchEvent specializations dispatch to it.
+template <>
+inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ art::Thread* thread,
+ JNIEnv* jnienv,
+ jclass class_being_redefined,
+ jobject loader,
+ const char* name,
+ jobject protection_domain,
+ jint class_data_len,
+ const unsigned char* class_data,
+ jint* new_class_data_len,
+ unsigned char** new_class_data) const {
+ return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ thread,
+ jnienv,
+ class_being_redefined,
+ loader,
+ name,
+ protection_domain,
+ class_data_len,
+ class_data,
+ new_class_data_len,
+ new_class_data);
+}
+template <>
+inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
+ art::Thread* thread,
+ JNIEnv* jnienv,
+ jclass class_being_redefined,
+ jobject loader,
+ const char* name,
+ jobject protection_domain,
+ jint class_data_len,
+ const unsigned char* class_data,
+ jint* new_class_data_len,
+ unsigned char** new_class_data) const {
+ return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
+ thread,
+ jnienv,
+ class_being_redefined,
+ loader,
+ name,
+ protection_domain,
+ class_data_len,
+ class_data,
+ new_class_data_len,
+ new_class_data);
+}
- if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(event)) {
+template <ArtJvmtiEvent kEvent>
+inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
+ art::Thread* thread) {
+ bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
+
+ if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
- dispatch = mask != nullptr && mask->Test(event);
+ dispatch = mask != nullptr && mask->Test(kEvent);
}
return dispatch;
}
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index d3f8001..1da08a0 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -206,13 +206,12 @@
ScopedLocalRef<jclass> klass(
jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
- handler_->DispatchEvent(self,
- ArtJvmtiEvent::kVmObjectAlloc,
- jni_env,
- thread.get(),
- object.get(),
- klass.get(),
- static_cast<jlong>(byte_count));
+ handler_->DispatchEvent<ArtJvmtiEvent::kVmObjectAlloc>(self,
+ reinterpret_cast<JNIEnv*>(jni_env),
+ thread.get(),
+ object.get(),
+ klass.get(),
+ static_cast<jlong>(byte_count));
}
}
@@ -241,11 +240,11 @@
finish_enabled_(false) {}
void StartPause() OVERRIDE {
- handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kGarbageCollectionStart);
+ handler_->DispatchEvent<ArtJvmtiEvent::kGarbageCollectionStart>(nullptr);
}
void EndPause() OVERRIDE {
- handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kGarbageCollectionFinish);
+ handler_->DispatchEvent<ArtJvmtiEvent::kGarbageCollectionFinish>(nullptr);
}
bool IsEnabled() {
diff --git a/runtime/openjdkjvmti/events.h b/runtime/openjdkjvmti/events.h
index 8e246de..4e20d17 100644
--- a/runtime/openjdkjvmti/events.h
+++ b/runtime/openjdkjvmti/events.h
@@ -156,9 +156,9 @@
ArtJvmtiEvent event,
jvmtiEventMode mode);
- template <typename ...Args>
+ template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
- inline void DispatchEvent(art::Thread* thread, ArtJvmtiEvent event, Args... args) const;
+ inline void DispatchEvent(art::Thread* thread, Args... args) const;
// Tell the event handler capabilities were added/lost so it can adjust the sent events.If
// caps_added is true then caps is all the newly set capabilities of the jvmtiEnv. If it is false
@@ -169,8 +169,9 @@
bool added);
private:
+ template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE
- static inline bool ShouldDispatch(ArtJvmtiEvent event, ArtJvmTiEnv* env, art::Thread* thread);
+ static inline bool ShouldDispatch(ArtJvmTiEnv* env, art::Thread* thread);
ALWAYS_INLINE
inline bool NeedsEventUpdate(ArtJvmTiEnv* env,
@@ -181,14 +182,17 @@
ALWAYS_INLINE
inline void RecalculateGlobalEventMask(ArtJvmtiEvent event);
- template <typename ...Args>
- ALWAYS_INLINE inline void GenericDispatchEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const;
- template <typename ...Args>
+ template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE inline void DispatchClassFileLoadHookEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const;
+ JNIEnv* jnienv,
+ jclass class_being_redefined,
+ jobject loader,
+ const char* name,
+ jobject protection_domain,
+ jint class_data_len,
+ const unsigned char* class_data,
+ jint* new_class_data_len,
+ unsigned char** new_class_data) const;
void HandleEventType(ArtJvmtiEvent event, bool enable);
diff --git a/runtime/openjdkjvmti/object_tagging.cc b/runtime/openjdkjvmti/object_tagging.cc
index 94cb46a..b27c2a3 100644
--- a/runtime/openjdkjvmti/object_tagging.cc
+++ b/runtime/openjdkjvmti/object_tagging.cc
@@ -207,7 +207,7 @@
}
void ObjectTagTable::HandleNullSweep(jlong tag) {
- event_handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kObjectFree, tag);
+ event_handler_->DispatchEvent<ArtJvmtiEvent::kObjectFree>(nullptr, tag);
}
template <typename T, ObjectTagTable::TableUpdateNullTarget kTargetNull>
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 450f75a..6dbab86 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -57,15 +57,15 @@
art::Thread* thread = art::Thread::Current();
ScopedLocalRef<jclass> jklass(thread->GetJniEnv(),
thread->GetJniEnv()->AddLocalReference<jclass>(klass.Get()));
- ScopedLocalRef<jclass> jthread(
- thread->GetJniEnv(), thread->GetJniEnv()->AddLocalReference<jclass>(thread->GetPeer()));
+ ScopedLocalRef<jthread> thread_jni(
+ thread->GetJniEnv(), thread->GetJniEnv()->AddLocalReference<jthread>(thread->GetPeer()));
{
art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
- event_handler->DispatchEvent(thread,
- ArtJvmtiEvent::kClassLoad,
- reinterpret_cast<JNIEnv*>(thread->GetJniEnv()),
- jthread.get(),
- jklass.get());
+ event_handler->DispatchEvent<ArtJvmtiEvent::kClassLoad>(
+ thread,
+ static_cast<JNIEnv*>(thread->GetJniEnv()),
+ thread_jni.get(),
+ jklass.get());
}
AddTempClass(thread, jklass.get());
}
@@ -78,14 +78,14 @@
art::Thread* thread = art::Thread::Current();
ScopedLocalRef<jclass> jklass(thread->GetJniEnv(),
thread->GetJniEnv()->AddLocalReference<jclass>(klass.Get()));
- ScopedLocalRef<jclass> jthread(
- thread->GetJniEnv(), thread->GetJniEnv()->AddLocalReference<jclass>(thread->GetPeer()));
+ ScopedLocalRef<jthread> thread_jni(
+ thread->GetJniEnv(), thread->GetJniEnv()->AddLocalReference<jthread>(thread->GetPeer()));
art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
- event_handler->DispatchEvent(thread,
- ArtJvmtiEvent::kClassPrepare,
- reinterpret_cast<JNIEnv*>(thread->GetJniEnv()),
- jthread.get(),
- jklass.get());
+ event_handler->DispatchEvent<ArtJvmtiEvent::kClassPrepare>(
+ thread,
+ static_cast<JNIEnv*>(thread->GetJniEnv()),
+ thread_jni.get(),
+ jklass.get());
}
}
diff --git a/runtime/openjdkjvmti/ti_dump.cc b/runtime/openjdkjvmti/ti_dump.cc
index 2ee5c40..d9e3ef1 100644
--- a/runtime/openjdkjvmti/ti_dump.cc
+++ b/runtime/openjdkjvmti/ti_dump.cc
@@ -48,7 +48,7 @@
void SigQuit() OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
art::Thread* thread = art::Thread::Current();
art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
- event_handler->DispatchEvent(nullptr, ArtJvmtiEvent::kDataDumpRequest);
+ event_handler->DispatchEvent<ArtJvmtiEvent::kDataDumpRequest>(nullptr);
}
EventHandler* event_handler = nullptr;
diff --git a/runtime/openjdkjvmti/ti_phase.cc b/runtime/openjdkjvmti/ti_phase.cc
index 154406a..4970288 100644
--- a/runtime/openjdkjvmti/ti_phase.cc
+++ b/runtime/openjdkjvmti/ti_phase.cc
@@ -64,7 +64,7 @@
case RuntimePhase::kStart:
{
art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative);
- event_handler->DispatchEvent(nullptr, ArtJvmtiEvent::kVmStart, GetJniEnv());
+ event_handler->DispatchEvent<ArtJvmtiEvent::kVmStart>(nullptr, GetJniEnv());
PhaseUtil::current_phase_ = JVMTI_PHASE_START;
}
break;
@@ -72,17 +72,14 @@
{
ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread());
art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative);
- event_handler->DispatchEvent(nullptr,
- ArtJvmtiEvent::kVmInit,
- GetJniEnv(),
- thread.get());
+ event_handler->DispatchEvent<ArtJvmtiEvent::kVmInit>(nullptr, GetJniEnv(), thread.get());
PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
}
break;
case RuntimePhase::kDeath:
{
art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative);
- event_handler->DispatchEvent(nullptr, ArtJvmtiEvent::kVmDeath, GetJniEnv());
+ event_handler->DispatchEvent<ArtJvmtiEvent::kVmDeath>(nullptr, GetJniEnv());
PhaseUtil::current_phase_ = JVMTI_PHASE_DEAD;
}
// TODO: Block events now.
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index 9f81d6b..b18a5cd 100644
--- a/runtime/openjdkjvmti/ti_thread.cc
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -61,11 +61,14 @@
}
return self->GetJniEnv()->AddLocalReference<jthread>(self->GetPeer());
}
- void Post(art::Thread* self, ArtJvmtiEvent type) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ template <ArtJvmtiEvent kEvent>
+ void Post(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
DCHECK_EQ(self, art::Thread::Current());
ScopedLocalRef<jthread> thread(self->GetJniEnv(), GetThreadObject(self));
art::ScopedThreadSuspension sts(self, art::ThreadState::kNative);
- event_handler->DispatchEvent(self, type, self->GetJniEnv(), thread.get());
+ event_handler->DispatchEvent<kEvent>(self,
+ reinterpret_cast<JNIEnv*>(self->GetJniEnv()),
+ thread.get());
}
void ThreadStart(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -81,11 +84,11 @@
}
return;
}
- Post(self, ArtJvmtiEvent::kThreadStart);
+ Post<ArtJvmtiEvent::kThreadStart>(self);
}
void ThreadDeath(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
- Post(self, ArtJvmtiEvent::kThreadEnd);
+ Post<ArtJvmtiEvent::kThreadEnd>(self);
}
void NextRuntimePhase(RuntimePhase phase) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -93,7 +96,7 @@
// We moved to VMInit. Report the main thread as started (it was attached early, and must
// not be reported until Init.
started = true;
- Post(art::Thread::Current(), ArtJvmtiEvent::kThreadStart);
+ Post<ArtJvmtiEvent::kThreadStart>(art::Thread::Current());
}
}
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index af4fb71..745c0f5 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -68,19 +68,17 @@
for (ArtClassDefinition& def : *definitions) {
jint new_len = -1;
unsigned char* new_data = nullptr;
- // Static casts are so that we get the right template initialization for the special event
- // handling code required by the ClassFileLoadHooks.
- gEventHandler.DispatchEvent(self,
- ArtJvmtiEvent::kClassFileLoadHookRetransformable,
- GetJniEnv(env),
- static_cast<jclass>(def.klass),
- static_cast<jobject>(def.loader),
- static_cast<const char*>(def.name.c_str()),
- static_cast<jobject>(def.protection_domain),
- static_cast<jint>(def.dex_len),
- static_cast<const unsigned char*>(def.dex_data.get()),
- static_cast<jint*>(&new_len),
- static_cast<unsigned char**>(&new_data));
+ gEventHandler.DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ self,
+ GetJniEnv(env),
+ def.klass,
+ def.loader,
+ def.name.c_str(),
+ def.protection_domain,
+ def.dex_len,
+ static_cast<const unsigned char*>(def.dex_data.get()),
+ &new_len,
+ &new_data);
def.SetNewDexData(env, new_len, new_data);
}
return OK;