diff options
-rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 18 | ||||
-rw-r--r-- | runtime/openjdkjvmti/events-inl.h | 52 | ||||
-rw-r--r-- | runtime/openjdkjvmti/events.cc | 45 | ||||
-rw-r--r-- | runtime/openjdkjvmti/events.h | 38 |
4 files changed, 131 insertions, 22 deletions
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index 195f179d3c..90467db8f6 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -905,11 +905,15 @@ class JvmtiFunctions { ENSURE_NON_NULL(capabilities_ptr); ArtJvmTiEnv* art_env = static_cast<ArtJvmTiEnv*>(env); jvmtiError ret = OK; + jvmtiCapabilities changed; #define ADD_CAPABILITY(e) \ do { \ if (capabilities_ptr->e == 1) { \ if (kPotentialCapabilities.e == 1) { \ - art_env->capabilities.e = 1;\ + if (art_env->capabilities.e != 1) { \ + art_env->capabilities.e = 1; \ + changed.e = 1; \ + }\ } else { \ ret = ERR(NOT_AVAILABLE); \ } \ @@ -958,6 +962,9 @@ class JvmtiFunctions { ADD_CAPABILITY(can_generate_resource_exhaustion_heap_events); ADD_CAPABILITY(can_generate_resource_exhaustion_threads_events); #undef ADD_CAPABILITY + gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), + changed, + /*added*/true); return ret; } @@ -966,10 +973,14 @@ class JvmtiFunctions { ENSURE_VALID_ENV(env); ENSURE_NON_NULL(capabilities_ptr); ArtJvmTiEnv* art_env = reinterpret_cast<ArtJvmTiEnv*>(env); + jvmtiCapabilities changed; #define DEL_CAPABILITY(e) \ do { \ if (capabilities_ptr->e == 1) { \ - art_env->capabilities.e = 0;\ + if (art_env->capabilities.e == 1) { \ + art_env->capabilities.e = 0;\ + changed.e = 1; \ + } \ } \ } while (false) @@ -1015,6 +1026,9 @@ class JvmtiFunctions { DEL_CAPABILITY(can_generate_resource_exhaustion_heap_events); DEL_CAPABILITY(can_generate_resource_exhaustion_threads_events); #undef DEL_CAPABILITY + gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), + changed, + /*added*/false); return OK; } diff --git a/runtime/openjdkjvmti/events-inl.h b/runtime/openjdkjvmti/events-inl.h index fb39db5da9..1e07bc6b7b 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 @@ ALWAYS_INLINE static inline FnType* GetCallback(ArtJvmTiEnv* env, ArtJvmtiEvent 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 @@ inline bool EventHandler::ShouldDispatch(ArtJvmtiEvent event, 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_ diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc index 66929cf8ab..f38aa869d9 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::DisableEvent(art::Thread* thread, ArtJvmtiEvent event) { } } +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 @@ jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env, 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); diff --git a/runtime/openjdkjvmti/events.h b/runtime/openjdkjvmti/events.h index 8f56145217..7990141562 100644 --- a/runtime/openjdkjvmti/events.h +++ b/runtime/openjdkjvmti/events.h @@ -30,14 +30,15 @@ struct ArtJvmTiEnv; class JvmtiAllocationListener; class JvmtiGcPauseListener; -// an enum for ArtEvents. +// an enum for ArtEvents. This differs from the JVMTI events only in that we distinguish between +// retransformation capable and incapable loading enum class ArtJvmtiEvent { kMinEventTypeVal = JVMTI_MIN_EVENT_TYPE_VAL, kVmInit = JVMTI_EVENT_VM_INIT, kVmDeath = JVMTI_EVENT_VM_DEATH, kThreadStart = JVMTI_EVENT_THREAD_START, kThreadEnd = JVMTI_EVENT_THREAD_END, - kClassFileLoadHook = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, + kClassFileLoadHookNonRetransformable = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, kClassLoad = JVMTI_EVENT_CLASS_LOAD, kClassPrepare = JVMTI_EVENT_CLASS_PREPARE, kVmStart = JVMTI_EVENT_VM_START, @@ -64,14 +65,19 @@ enum class ArtJvmtiEvent { kGarbageCollectionFinish = JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, kObjectFree = JVMTI_EVENT_OBJECT_FREE, kVmObjectAlloc = JVMTI_EVENT_VM_OBJECT_ALLOC, - kMaxEventTypeVal = JVMTI_MAX_EVENT_TYPE_VAL, + kClassFileLoadHookRetransformable = JVMTI_MAX_EVENT_TYPE_VAL + 1, + kMaxEventTypeVal = kClassFileLoadHookRetransformable, }; // Convert a jvmtiEvent into a ArtJvmtiEvent ALWAYS_INLINE static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e); -ALWAYS_INLINE static inline jvmtiEvent GetJvmtiEvent(ArtJvmtiEvent e) { - return static_cast<jvmtiEvent>(e); +static inline jvmtiEvent GetJvmtiEvent(ArtJvmtiEvent e) { + if (UNLIKELY(e == ArtJvmtiEvent::kClassFileLoadHookRetransformable)) { + return JVMTI_EVENT_CLASS_FILE_LOAD_HOOK; + } else { + return static_cast<jvmtiEvent>(e); + } } struct EventMask { @@ -118,6 +124,11 @@ struct EventMasks { EventMask* GetEventMaskOrNull(art::Thread* thread); void EnableEvent(art::Thread* thread, ArtJvmtiEvent event); void DisableEvent(art::Thread* thread, ArtJvmtiEvent event); + bool IsEnabledAnywhere(ArtJvmtiEvent event); + // Make any changes to event masks needed for the given capability changes. If caps_added is true + // then caps is all the newly set capabilities of the jvmtiEnv. If it is false then caps is the + // set of all capabilities that were removed from the jvmtiEnv. + void HandleChangedCapabilities(const jvmtiCapabilities& caps, bool caps_added); }; // Helper class for event handling. @@ -146,10 +157,27 @@ class EventHandler { ALWAYS_INLINE inline void DispatchEvent(art::Thread* thread, ArtJvmtiEvent event, 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 + // then caps is the set of all capabilities that were removed from the jvmtiEnv. + ALWAYS_INLINE + inline void HandleChangedCapabilities(ArtJvmTiEnv* env, + const jvmtiCapabilities& caps, + bool added); + private: ALWAYS_INLINE static inline bool ShouldDispatch(ArtJvmtiEvent event, ArtJvmTiEnv* env, art::Thread* thread); + ALWAYS_INLINE + inline bool NeedsEventUpdate(ArtJvmTiEnv* env, + const jvmtiCapabilities& caps, + bool added); + + // Recalculates the event mask for the given event. + ALWAYS_INLINE + inline void RecalculateGlobalEventMask(ArtJvmtiEvent event); + void HandleEventType(ArtJvmtiEvent event, bool enable); // List of all JvmTiEnv objects that have been created, in their creation order. |