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.cc b/runtime/openjdkjvmti/events.cc
index 66929cf..f38aa86 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -47,6 +47,10 @@
namespace openjdkjvmti {
+bool EventMasks::IsEnabledAnywhere(ArtJvmtiEvent event) {
+ return global_event_mask.Test(event) || unioned_thread_event_mask.Test(event);
+}
+
EventMask& EventMasks::GetEventMask(art::Thread* thread) {
if (thread == nullptr) {
return global_event_mask;
@@ -107,6 +111,35 @@
}
}
+void EventMasks::HandleChangedCapabilities(const jvmtiCapabilities& caps, bool caps_added) {
+ if (UNLIKELY(caps.can_retransform_classes == 1)) {
+ // If we are giving this env the retransform classes cap we need to switch all events of
+ // NonTransformable to Transformable and vice versa.
+ ArtJvmtiEvent to_remove = caps_added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
+ : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
+ ArtJvmtiEvent to_add = caps_added ? ArtJvmtiEvent::kClassFileLoadHookRetransformable
+ : ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
+ if (global_event_mask.Test(to_remove)) {
+ CHECK(!global_event_mask.Test(to_add));
+ global_event_mask.Set(to_remove, false);
+ global_event_mask.Set(to_add, true);
+ }
+
+ if (unioned_thread_event_mask.Test(to_remove)) {
+ CHECK(!unioned_thread_event_mask.Test(to_add));
+ unioned_thread_event_mask.Set(to_remove, false);
+ unioned_thread_event_mask.Set(to_add, true);
+ }
+ for (auto thread_mask : thread_event_masks) {
+ if (thread_mask.second.Test(to_remove)) {
+ CHECK(!thread_mask.second.Test(to_add));
+ thread_mask.second.Set(to_remove, false);
+ thread_mask.second.Set(to_add, true);
+ }
+ }
+ }
+}
+
void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
envs.push_back(env);
}
@@ -293,17 +326,7 @@
DCHECK_EQ(mode, JVMTI_DISABLE);
env->event_masks.DisableEvent(thread, event);
-
- // Gotta recompute the global mask.
- 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);
+ RecalculateGlobalEventMask(event);
}
bool new_state = global_mask.Test(event);