OSDN Git Service

ART: Refactor TI events
authorAndreas Gampe <agampe@google.com>
Tue, 24 Jan 2017 03:46:56 +0000 (19:46 -0800)
committerAndreas Gampe <agampe@google.com>
Tue, 24 Jan 2017 23:21:18 +0000 (15:21 -0800)
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

runtime/openjdkjvmti/events-inl.h
runtime/openjdkjvmti/events.cc
runtime/openjdkjvmti/events.h
runtime/openjdkjvmti/object_tagging.cc
runtime/openjdkjvmti/ti_class.cc
runtime/openjdkjvmti/ti_dump.cc
runtime/openjdkjvmti/ti_phase.cc
runtime/openjdkjvmti/ti_thread.cc
runtime/openjdkjvmti/transform.cc

index 21ec731..655a53a 100644 (file)
@@ -37,96 +37,84 @@ static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
   }
 }
 
-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)
 
-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!";
+#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;                                      \
 }
 
+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 @@ inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
                                                          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 @@ inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
   }
 }
 
-template <typename ...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.
+
+template <ArtJvmtiEvent kEvent, 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...);
-  }
-}
-
-// TODO Locking of some type!
-template <typename ...Args>
-inline void EventHandler::GenericDispatchEvent(art::Thread* thread,
-                                               ArtJvmtiEvent event,
-                                               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 void EventHandler::GenericDispatchEvent(art::Thread* thread,
   }
 }
 
-inline bool EventHandler::ShouldDispatch(ArtJvmtiEvent event,
-                                         ArtJvmTiEnv* env,
+// 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);
+}
+
+template <ArtJvmtiEvent kEvent>
+inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
                                          art::Thread* thread) {
-  bool dispatch = env->event_masks.global_event_mask.Test(event);
+  bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
 
-  if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(event)) {
+  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;
 }
index d3f8001..1da08a0 100644 (file)
@@ -206,13 +206,12 @@ class JvmtiAllocationListener : public art::gc::AllocationListener {
       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 @@ class JvmtiGcPauseListener : public art::gc::GcPauseListener {
         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() {
index 8e246de..4e20d17 100644 (file)
@@ -156,9 +156,9 @@ class EventHandler {
                       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 @@ class EventHandler {
                                         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 @@ class EventHandler {
   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);
 
index 94cb46a..b27c2a3 100644 (file)
@@ -207,7 +207,7 @@ void ObjectTagTable::SweepImpl(art::IsMarkedVisitor* visitor) {
 }
 
 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>
index 450f75a..6dbab86 100644 (file)
@@ -57,15 +57,15 @@ struct ClassCallback : public art::ClassLoadCallback {
       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 @@ struct ClassCallback : public art::ClassLoadCallback {
       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());
     }
   }
 
index 2ee5c40..d9e3ef1 100644 (file)
@@ -48,7 +48,7 @@ struct DumpCallback : public art::RuntimeSigQuitCallback {
   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;
index 154406a..4970288 100644 (file)
@@ -64,7 +64,7 @@ struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback {
       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 @@ struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback {
         {
           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.
index 9f81d6b..b18a5cd 100644 (file)
@@ -61,11 +61,14 @@ struct ThreadCallback : public art::ThreadLifecycleCallback, public art::Runtime
     }
     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 @@ struct ThreadCallback : public art::ThreadLifecycleCallback, public art::Runtime
       }
       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 @@ struct ThreadCallback : public art::ThreadLifecycleCallback, public art::Runtime
       // 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());
     }
   }
 
index af4fb71..745c0f5 100644 (file)
@@ -68,19 +68,17 @@ jvmtiError Transformer::RetransformClassesDirect(
   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;