1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_H_ 18#define ART_RUNTIME_OPENJDKJVMTI_EVENTS_H_ 19 20#include <bitset> 21#include <vector> 22 23#include "base/logging.h" 24#include "jvmti.h" 25#include "thread.h" 26 27namespace openjdkjvmti { 28 29struct ArtJvmTiEnv; 30class JvmtiAllocationListener; 31class JvmtiGcPauseListener; 32 33// an enum for ArtEvents. This differs from the JVMTI events only in that we distinguish between 34// retransformation capable and incapable loading 35enum class ArtJvmtiEvent { 36 kMinEventTypeVal = JVMTI_MIN_EVENT_TYPE_VAL, 37 kVmInit = JVMTI_EVENT_VM_INIT, 38 kVmDeath = JVMTI_EVENT_VM_DEATH, 39 kThreadStart = JVMTI_EVENT_THREAD_START, 40 kThreadEnd = JVMTI_EVENT_THREAD_END, 41 kClassFileLoadHookNonRetransformable = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, 42 kClassLoad = JVMTI_EVENT_CLASS_LOAD, 43 kClassPrepare = JVMTI_EVENT_CLASS_PREPARE, 44 kVmStart = JVMTI_EVENT_VM_START, 45 kException = JVMTI_EVENT_EXCEPTION, 46 kExceptionCatch = JVMTI_EVENT_EXCEPTION_CATCH, 47 kSingleStep = JVMTI_EVENT_SINGLE_STEP, 48 kFramePop = JVMTI_EVENT_FRAME_POP, 49 kBreakpoint = JVMTI_EVENT_BREAKPOINT, 50 kFieldAccess = JVMTI_EVENT_FIELD_ACCESS, 51 kFieldModification = JVMTI_EVENT_FIELD_MODIFICATION, 52 kMethodEntry = JVMTI_EVENT_METHOD_ENTRY, 53 kMethodExit = JVMTI_EVENT_METHOD_EXIT, 54 kNativeMethodBind = JVMTI_EVENT_NATIVE_METHOD_BIND, 55 kCompiledMethodLoad = JVMTI_EVENT_COMPILED_METHOD_LOAD, 56 kCompiledMethodUnload = JVMTI_EVENT_COMPILED_METHOD_UNLOAD, 57 kDynamicCodeGenerated = JVMTI_EVENT_DYNAMIC_CODE_GENERATED, 58 kDataDumpRequest = JVMTI_EVENT_DATA_DUMP_REQUEST, 59 kMonitorWait = JVMTI_EVENT_MONITOR_WAIT, 60 kMonitorWaited = JVMTI_EVENT_MONITOR_WAITED, 61 kMonitorContendedEnter = JVMTI_EVENT_MONITOR_CONTENDED_ENTER, 62 kMonitorContendedEntered = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, 63 kResourceExhausted = JVMTI_EVENT_RESOURCE_EXHAUSTED, 64 kGarbageCollectionStart = JVMTI_EVENT_GARBAGE_COLLECTION_START, 65 kGarbageCollectionFinish = JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, 66 kObjectFree = JVMTI_EVENT_OBJECT_FREE, 67 kVmObjectAlloc = JVMTI_EVENT_VM_OBJECT_ALLOC, 68 kClassFileLoadHookRetransformable = JVMTI_MAX_EVENT_TYPE_VAL + 1, 69 kMaxEventTypeVal = kClassFileLoadHookRetransformable, 70}; 71 72// Convert a jvmtiEvent into a ArtJvmtiEvent 73ALWAYS_INLINE static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e); 74 75static inline jvmtiEvent GetJvmtiEvent(ArtJvmtiEvent e) { 76 if (UNLIKELY(e == ArtJvmtiEvent::kClassFileLoadHookRetransformable)) { 77 return JVMTI_EVENT_CLASS_FILE_LOAD_HOOK; 78 } else { 79 return static_cast<jvmtiEvent>(e); 80 } 81} 82 83struct EventMask { 84 static constexpr size_t kEventsSize = 85 static_cast<size_t>(ArtJvmtiEvent::kMaxEventTypeVal) - 86 static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal) + 1; 87 std::bitset<kEventsSize> bit_set; 88 89 static bool EventIsInRange(ArtJvmtiEvent event) { 90 return event >= ArtJvmtiEvent::kMinEventTypeVal && event <= ArtJvmtiEvent::kMaxEventTypeVal; 91 } 92 93 void Set(ArtJvmtiEvent event, bool value = true) { 94 DCHECK(EventIsInRange(event)); 95 bit_set.set(static_cast<size_t>(event) - static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal), 96 value); 97 } 98 99 bool Test(ArtJvmtiEvent event) const { 100 DCHECK(EventIsInRange(event)); 101 return bit_set.test( 102 static_cast<size_t>(event) - static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal)); 103 } 104}; 105 106struct EventMasks { 107 // The globally enabled events. 108 EventMask global_event_mask; 109 110 // The per-thread enabled events. 111 112 // It is not enough to store a Thread pointer, as these may be reused. Use the pointer and the 113 // thread id. 114 // Note: We could just use the tid like tracing does. 115 using UniqueThread = std::pair<art::Thread*, uint32_t>; 116 // TODO: Native thread objects are immovable, so we can use them as keys in an (unordered) map, 117 // if necessary. 118 std::vector<std::pair<UniqueThread, EventMask>> thread_event_masks; 119 120 // A union of the per-thread events, for fast-pathing. 121 EventMask unioned_thread_event_mask; 122 123 EventMask& GetEventMask(art::Thread* thread); 124 EventMask* GetEventMaskOrNull(art::Thread* thread); 125 void EnableEvent(art::Thread* thread, ArtJvmtiEvent event); 126 void DisableEvent(art::Thread* thread, ArtJvmtiEvent event); 127 bool IsEnabledAnywhere(ArtJvmtiEvent event); 128 // Make any changes to event masks needed for the given capability changes. If caps_added is true 129 // then caps is all the newly set capabilities of the jvmtiEnv. If it is false then caps is the 130 // set of all capabilities that were removed from the jvmtiEnv. 131 void HandleChangedCapabilities(const jvmtiCapabilities& caps, bool caps_added); 132}; 133 134// Helper class for event handling. 135class EventHandler { 136 public: 137 EventHandler(); 138 ~EventHandler(); 139 140 // Register an env. It is assumed that this happens on env creation, that is, no events are 141 // enabled, yet. 142 void RegisterArtJvmTiEnv(ArtJvmTiEnv* env); 143 144 // Remove an env. 145 void RemoveArtJvmTiEnv(ArtJvmTiEnv* env); 146 147 bool IsEventEnabledAnywhere(ArtJvmtiEvent event) const { 148 if (!EventMask::EventIsInRange(event)) { 149 return false; 150 } 151 return global_mask.Test(event); 152 } 153 154 jvmtiError SetEvent(ArtJvmTiEnv* env, 155 art::Thread* thread, 156 ArtJvmtiEvent event, 157 jvmtiEventMode mode); 158 159 // Dispatch event to all registered environments. 160 template <ArtJvmtiEvent kEvent, typename ...Args> 161 ALWAYS_INLINE 162 inline void DispatchEvent(art::Thread* thread, Args... args) const; 163 // Dispatch event to the given environment, only. 164 template <ArtJvmtiEvent kEvent, typename ...Args> 165 ALWAYS_INLINE 166 inline void DispatchEvent(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const; 167 168 // Tell the event handler capabilities were added/lost so it can adjust the sent events.If 169 // caps_added is true then caps is all the newly set capabilities of the jvmtiEnv. If it is false 170 // then caps is the set of all capabilities that were removed from the jvmtiEnv. 171 ALWAYS_INLINE 172 inline void HandleChangedCapabilities(ArtJvmTiEnv* env, 173 const jvmtiCapabilities& caps, 174 bool added); 175 176 private: 177 template <ArtJvmtiEvent kEvent> 178 ALWAYS_INLINE 179 static inline bool ShouldDispatch(ArtJvmTiEnv* env, art::Thread* thread); 180 181 ALWAYS_INLINE 182 inline bool NeedsEventUpdate(ArtJvmTiEnv* env, 183 const jvmtiCapabilities& caps, 184 bool added); 185 186 // Recalculates the event mask for the given event. 187 ALWAYS_INLINE 188 inline void RecalculateGlobalEventMask(ArtJvmtiEvent event); 189 190 template <ArtJvmtiEvent kEvent> 191 ALWAYS_INLINE inline void DispatchClassFileLoadHookEvent(art::Thread* thread, 192 JNIEnv* jnienv, 193 jclass class_being_redefined, 194 jobject loader, 195 const char* name, 196 jobject protection_domain, 197 jint class_data_len, 198 const unsigned char* class_data, 199 jint* new_class_data_len, 200 unsigned char** new_class_data) const; 201 202 void HandleEventType(ArtJvmtiEvent event, bool enable); 203 204 // List of all JvmTiEnv objects that have been created, in their creation order. 205 // NB Some elements might be null representing envs that have been deleted. They should be skipped 206 // anytime this list is used. 207 std::vector<ArtJvmTiEnv*> envs; 208 209 // A union of all enabled events, anywhere. 210 EventMask global_mask; 211 212 std::unique_ptr<JvmtiAllocationListener> alloc_listener_; 213 std::unique_ptr<JvmtiGcPauseListener> gc_pause_listener_; 214}; 215 216} // namespace openjdkjvmti 217 218#endif // ART_RUNTIME_OPENJDKJVMTI_EVENTS_H_ 219