Split ArtJvmtiEvent::kClassFileLoadHook in two.

Since the ClassFileLoadHook event is sent to different environments
based on when it is invoked we split the event in two behind the
scenes. The event dispatcher is responsible for making sure that
either or both of the appropriate underlying events are invoked when a
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK is sent.

We also make sure to modify the EventHandler so it sends the correct
events in the correct places when an environment changes its
capabilities.

Bug: 32369913
Bug: 31684920

Test: mma -j40 test-art-host

Change-Id: I82567fc66debe0b658e8d7fced6284a8c4355b7a
diff --git a/runtime/openjdkjvmti/events-inl.h b/runtime/openjdkjvmti/events-inl.h
index fb39db5..1e07bc6 100644
--- a/runtime/openjdkjvmti/events-inl.h
+++ b/runtime/openjdkjvmti/events-inl.h
@@ -17,15 +17,24 @@
 #ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
 #define ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
 
+#include <array>
+
 #include "events.h"
 
 #include "art_jvmti.h"
 
 namespace openjdkjvmti {
 
-static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env ATTRIBUTE_UNUSED,
-                                                           jvmtiEvent e) {
-  return static_cast<ArtJvmtiEvent>(e);
+static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
+  if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
+    if (env->capabilities.can_retransform_classes) {
+      return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
+    } else {
+      return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
+    }
+  } else {
+    return static_cast<ArtJvmtiEvent>(e);
+  }
 }
 
 template <typename FnType>
@@ -46,7 +55,8 @@
       return reinterpret_cast<FnType*>(env->event_callbacks->ThreadStart);
     case ArtJvmtiEvent::kThreadEnd:
       return reinterpret_cast<FnType*>(env->event_callbacks->ThreadEnd);
-    case ArtJvmtiEvent::kClassFileLoadHook:
+    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);
@@ -131,6 +141,40 @@
   return dispatch;
 }
 
+inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
+  bool union_value = false;
+  for (const ArtJvmTiEnv* stored_env : envs) {
+    union_value |= stored_env->event_masks.global_event_mask.Test(event);
+    union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
+    if (union_value) {
+      break;
+    }
+  }
+  global_mask.Set(event, union_value);
+}
+
+inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
+                                           const jvmtiCapabilities& caps,
+                                           bool added) {
+  ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
+                              : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
+  return caps.can_retransform_classes == 1 &&
+      IsEventEnabledAnywhere(event) &&
+      env->event_masks.IsEnabledAnywhere(event);
+}
+
+inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
+                                                    const jvmtiCapabilities& caps,
+                                                    bool added) {
+  if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
+    env->event_masks.HandleChangedCapabilities(caps, added);
+    if (caps.can_retransform_classes == 1) {
+      RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
+      RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
+    }
+  }
+}
+
 }  // namespace openjdkjvmti
 
 #endif  // ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_