1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
|
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ART_OPENJDKJVMTI_EVENTS_H_
#define ART_OPENJDKJVMTI_EVENTS_H_
#include <bitset>
#include <unordered_map>
#include <vector>
#include "android-base/logging.h"
#include "android-base/thread_annotations.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "jvmti.h"
#include "managed_stack.h"
#include "thread.h"
namespace openjdkjvmti {
struct ArtJvmTiEnv;
class JvmtiEventAllocationListener;
class JvmtiDdmChunkListener;
class JvmtiGcPauseListener;
class JvmtiMethodTraceListener;
class JvmtiMonitorListener;
class JvmtiParkListener;
// an enum for ArtEvents. This differs from the JVMTI events only in that we distinguish between
// retransformation capable and incapable loading
enum class ArtJvmtiEvent : jint {
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,
kClassFileLoadHookNonRetransformable = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
kClassLoad = JVMTI_EVENT_CLASS_LOAD,
kClassPrepare = JVMTI_EVENT_CLASS_PREPARE,
kVmStart = JVMTI_EVENT_VM_START,
kException = JVMTI_EVENT_EXCEPTION,
kExceptionCatch = JVMTI_EVENT_EXCEPTION_CATCH,
kSingleStep = JVMTI_EVENT_SINGLE_STEP,
kFramePop = JVMTI_EVENT_FRAME_POP,
kBreakpoint = JVMTI_EVENT_BREAKPOINT,
kFieldAccess = JVMTI_EVENT_FIELD_ACCESS,
kFieldModification = JVMTI_EVENT_FIELD_MODIFICATION,
kMethodEntry = JVMTI_EVENT_METHOD_ENTRY,
kMethodExit = JVMTI_EVENT_METHOD_EXIT,
kNativeMethodBind = JVMTI_EVENT_NATIVE_METHOD_BIND,
kCompiledMethodLoad = JVMTI_EVENT_COMPILED_METHOD_LOAD,
kCompiledMethodUnload = JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
kDynamicCodeGenerated = JVMTI_EVENT_DYNAMIC_CODE_GENERATED,
kDataDumpRequest = JVMTI_EVENT_DATA_DUMP_REQUEST,
kMonitorWait = JVMTI_EVENT_MONITOR_WAIT,
kMonitorWaited = JVMTI_EVENT_MONITOR_WAITED,
kMonitorContendedEnter = JVMTI_EVENT_MONITOR_CONTENDED_ENTER,
kMonitorContendedEntered = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED,
kResourceExhausted = JVMTI_EVENT_RESOURCE_EXHAUSTED,
kGarbageCollectionStart = JVMTI_EVENT_GARBAGE_COLLECTION_START,
kGarbageCollectionFinish = JVMTI_EVENT_GARBAGE_COLLECTION_FINISH,
kObjectFree = JVMTI_EVENT_OBJECT_FREE,
kVmObjectAlloc = JVMTI_EVENT_VM_OBJECT_ALLOC,
// Internal event to mark a ClassFileLoadHook as one created with the can_retransform_classes
// capability.
kClassFileLoadHookRetransformable = JVMTI_MAX_EVENT_TYPE_VAL + 1,
kDdmPublishChunk = JVMTI_MAX_EVENT_TYPE_VAL + 2,
kObsoleteObjectCreated = JVMTI_MAX_EVENT_TYPE_VAL + 3,
kStructuralDexFileLoadHook = JVMTI_MAX_EVENT_TYPE_VAL + 4,
kMaxNormalEventTypeVal = kStructuralDexFileLoadHook,
// All that follow are events used to implement internal JVMTI functions. They are not settable
// directly by agents.
kMinInternalEventTypeVal = kMaxNormalEventTypeVal + 1,
// Internal event we use to implement the ForceEarlyReturn functions.
kForceEarlyReturnUpdateReturnValue = kMinInternalEventTypeVal,
kMaxInternalEventTypeVal = kForceEarlyReturnUpdateReturnValue,
kMaxEventTypeVal = kMaxInternalEventTypeVal,
};
constexpr jint kInternalEventCount = static_cast<jint>(ArtJvmtiEvent::kMaxInternalEventTypeVal) -
static_cast<jint>(ArtJvmtiEvent::kMinInternalEventTypeVal) + 1;
using ArtJvmtiEventDdmPublishChunk = void (*)(jvmtiEnv *jvmti_env,
jint data_type,
jint data_len,
const jbyte* data);
using ArtJvmtiEventObsoleteObjectCreated = void (*)(jvmtiEnv *jvmti_env,
jlong* obsolete_tag,
jlong* new_tag);
using ArtJvmtiEventStructuralDexFileLoadHook = void (*)(jvmtiEnv *jvmti_env,
JNIEnv* jni_env,
jclass class_being_redefined,
jobject loader,
const char* name,
jobject protection_domain,
jint dex_data_len,
const unsigned char* dex_data,
jint* new_dex_data_len,
unsigned char** new_dex_data);
// It is not enough to store a Thread pointer, as these may be reused. Use the pointer and the
// thread id.
// Note: We could just use the tid like tracing does.
using UniqueThread = std::pair<art::Thread*, uint32_t>;
struct UniqueThreadHasher {
std::size_t operator()(const UniqueThread& k) const {
return std::hash<uint32_t>{}(k.second) ^ (std::hash<void*>{}(k.first) << 1);
}
};
struct ArtJvmtiEventCallbacks : jvmtiEventCallbacks {
ArtJvmtiEventCallbacks()
: DdmPublishChunk(nullptr),
ObsoleteObjectCreated(nullptr),
StructuralDexFileLoadHook(nullptr) {
memset(this, 0, sizeof(jvmtiEventCallbacks));
}
// Copies extension functions from other callback struct if it exists. There must not have been
// any modifications to this struct when it is called.
void CopyExtensionsFrom(const ArtJvmtiEventCallbacks* cb);
jvmtiError Set(jint index, jvmtiExtensionEvent cb);
ArtJvmtiEventDdmPublishChunk DdmPublishChunk;
ArtJvmtiEventObsoleteObjectCreated ObsoleteObjectCreated;
ArtJvmtiEventStructuralDexFileLoadHook StructuralDexFileLoadHook;
};
bool IsExtensionEvent(jint e);
bool IsExtensionEvent(ArtJvmtiEvent e);
// Convert a jvmtiEvent into a ArtJvmtiEvent
ALWAYS_INLINE static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, 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 {
static constexpr size_t kEventsSize =
static_cast<size_t>(ArtJvmtiEvent::kMaxEventTypeVal) -
static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal) + 1;
std::bitset<kEventsSize> bit_set;
static bool EventIsInRange(ArtJvmtiEvent event) {
return event >= ArtJvmtiEvent::kMinEventTypeVal && event <= ArtJvmtiEvent::kMaxEventTypeVal;
}
void Set(ArtJvmtiEvent event, bool value = true) {
DCHECK(EventIsInRange(event));
bit_set.set(static_cast<size_t>(event) - static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal),
value);
}
bool Test(ArtJvmtiEvent event) const {
DCHECK(EventIsInRange(event));
return bit_set.test(
static_cast<size_t>(event) - static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal));
}
};
struct EventMasks {
// The globally enabled events.
EventMask global_event_mask;
// The per-thread enabled events.
// TODO: Native thread objects are immovable, so we can use them as keys in an (unordered) map,
// if necessary.
std::vector<std::pair<UniqueThread, EventMask>> thread_event_masks;
// A union of the per-thread events, for fast-pathing.
EventMask unioned_thread_event_mask;
EventMask& GetEventMask(art::Thread* thread);
EventMask* GetEventMaskOrNull(art::Thread* thread);
// Circular dependencies mean we cannot see the definition of ArtJvmTiEnv so the mutex is simply
// asserted in the function.
// Note that the 'env' passed in must be the same env this EventMasks is associated with.
void EnableEvent(ArtJvmTiEnv* env, art::Thread* thread, ArtJvmtiEvent event);
// REQUIRES(env->event_info_mutex_);
// Circular dependencies mean we cannot see the definition of ArtJvmTiEnv so the mutex is simply
// asserted in the function.
// Note that the 'env' passed in must be the same env this EventMasks is associated with.
void DisableEvent(ArtJvmTiEnv* env, art::Thread* thread, ArtJvmtiEvent event);
// REQUIRES(env->event_info_mutex_);
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);
};
namespace impl {
template <ArtJvmtiEvent kEvent> struct EventHandlerFunc { };
} // namespace impl
// Helper class for event handling.
class EventHandler {
public:
EventHandler();
~EventHandler();
// do cleanup for the event handler.
void Shutdown();
// Register an env. It is assumed that this happens on env creation, that is, no events are
// enabled, yet.
void RegisterArtJvmTiEnv(ArtJvmTiEnv* env) REQUIRES(!envs_lock_);
// Remove an env.
void RemoveArtJvmTiEnv(ArtJvmTiEnv* env) REQUIRES(!envs_lock_);
bool IsEventEnabledAnywhere(ArtJvmtiEvent event) const {
if (!EventMask::EventIsInRange(event)) {
return false;
}
return global_mask.Test(event);
}
// Sets an internal event. Unlike normal JVMTI events internal events are not associated with any
// particular jvmtiEnv and are refcounted. This refcounting is done to allow us to easily enable
// events during functions and disable them during the requested event callback. Since these are
// used to implement various JVMTI functions these events always have a single target thread. If
// target is null the current thread is used.
jvmtiError SetInternalEvent(jthread target,
ArtJvmtiEvent event,
jvmtiEventMode mode)
REQUIRES(!envs_lock_, !art::Locks::mutator_lock_);
jvmtiError SetEvent(ArtJvmTiEnv* env,
jthread thread,
ArtJvmtiEvent event,
jvmtiEventMode mode)
REQUIRES(!envs_lock_);
// Dispatch event to all registered environments. Since this one doesn't have a JNIEnv* it doesn't
// matter if it has the mutator_lock.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
inline void DispatchEvent(art::Thread* thread, Args... args) const
REQUIRES(!envs_lock_);
// Dispatch event to all registered environments stashing exceptions as needed. This works since
// JNIEnv* is always the second argument if it is passed to an event. Needed since C++ does not
// allow partial template function specialization.
//
// We need both of these since we want to make sure to push a stack frame when it is possible for
// the event to allocate local references.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
inline void DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const
REQUIRES(!envs_lock_);
// 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)
REQUIRES(!envs_lock_);
// Dispatch event to the given environment, only.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
inline void DispatchEventOnEnv(ArtJvmTiEnv* env,
art::Thread* thread,
JNIEnv* jnienv,
Args... args) const
REQUIRES(!envs_lock_);
// Dispatch event to the given environment, only.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
inline void DispatchEventOnEnv(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const
REQUIRES(!envs_lock_);
void AddDelayedNonStandardExitEvent(const art::ShadowFrame* frame, bool is_object, jvalue val)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(art::Locks::user_code_suspension_lock_, art::Locks::thread_list_lock_);
template<typename Visitor>
void ForEachEnv(art::Thread* self, Visitor v) REQUIRES(!envs_lock_) {
art::ReaderMutexLock mu(self, envs_lock_);
for (ArtJvmTiEnv* e : envs) {
if (e != nullptr) {
v(e);
}
}
}
private:
void SetupTraceListener(JvmtiMethodTraceListener* listener, ArtJvmtiEvent event, bool enable);
uint32_t GetInstrumentationEventsFor(ArtJvmtiEvent event);
// Specifically handle the FramePop event which it might not always be possible to turn off.
void SetupFramePopTraceListener(bool enable);
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
inline std::vector<impl::EventHandlerFunc<kEvent>> CollectEvents(art::Thread* thread,
Args... args) const
REQUIRES(!envs_lock_);
template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE
inline bool ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const;
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
static inline void ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
JNIEnv* env,
Args... args)
REQUIRES(!envs_lock_);
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
static inline void ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args)
REQUIRES(!envs_lock_);
// Public for use to collect dispatches
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
inline bool ShouldDispatch(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const;
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) REQUIRES(!envs_lock_);
ALWAYS_INLINE
inline void RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) REQUIRES_SHARED(envs_lock_);
// Returns whether there are any active requests for the given event on the given thread. This
// should only be used while modifying the events for a thread.
bool GetThreadEventState(ArtJvmtiEvent event, art::Thread* thread)
REQUIRES(envs_lock_, art::Locks::thread_list_lock_);
template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE inline void DispatchClassFileLoadHookEvent(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
REQUIRES(!envs_lock_);
template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE inline void DispatchClassLoadOrPrepareEvent(art::Thread* thread,
JNIEnv* jnienv,
jthread jni_thread,
jclass klass) const
REQUIRES(!envs_lock_);
// Sets up the global state needed for the first/last enable of an event across all threads
void HandleEventType(ArtJvmtiEvent event, bool enable);
// Perform deopts required for enabling the event on the given thread. Null thread indicates
// global event enabled.
jvmtiError HandleEventDeopt(ArtJvmtiEvent event, jthread thread, bool enable);
void HandleLocalAccessCapabilityAdded();
void HandleBreakpointEventsChanged(bool enable);
bool OtherMonitorEventsEnabledAnywhere(ArtJvmtiEvent event);
int32_t GetInternalEventRefcount(ArtJvmtiEvent event) const REQUIRES(envs_lock_);
// Increment internal event refcount for the given event and return the new count.
int32_t IncrInternalEventRefcount(ArtJvmtiEvent event) REQUIRES(envs_lock_);
// Decrement internal event refcount for the given event and return the new count.
int32_t DecrInternalEventRefcount(ArtJvmtiEvent event) REQUIRES(envs_lock_);
int32_t& GetInternalEventThreadRefcount(ArtJvmtiEvent event, art::Thread* target)
REQUIRES(envs_lock_, art::Locks::thread_list_lock_);
// Increment internal event refcount for the given event and return the new count.
int32_t IncrInternalEventThreadRefcount(ArtJvmtiEvent event, art::Thread* target)
REQUIRES(envs_lock_, art::Locks::thread_list_lock_);
// Decrement internal event refcount for the given event and return the new count.
int32_t DecrInternalEventThreadRefcount(ArtJvmtiEvent event, art::Thread* target)
REQUIRES(envs_lock_, art::Locks::thread_list_lock_);
// List of all JvmTiEnv objects that have been created, in their creation order. It is a std::list
// since we mostly access it by iterating over the entire thing, only ever append to the end, and
// need to be able to remove arbitrary elements from it.
std::list<ArtJvmTiEnv*> envs GUARDED_BY(envs_lock_);
// Close to top level lock. Nothing should be held when we lock this (except for mutator_lock_
// which is needed when setting new events).
mutable art::ReaderWriterMutex envs_lock_ ACQUIRED_AFTER(art::Locks::mutator_lock_);
// A union of all enabled events, anywhere.
EventMask global_mask;
std::unique_ptr<JvmtiEventAllocationListener> alloc_listener_;
std::unique_ptr<JvmtiDdmChunkListener> ddm_listener_;
std::unique_ptr<JvmtiGcPauseListener> gc_pause_listener_;
std::unique_ptr<JvmtiMethodTraceListener> method_trace_listener_;
std::unique_ptr<JvmtiMonitorListener> monitor_listener_;
std::unique_ptr<JvmtiParkListener> park_listener_;
// True if frame pop has ever been enabled. Since we store pointers to stack frames we need to
// continue to listen to this event even if it has been disabled.
// TODO We could remove the listeners once all jvmtiEnvs have drained their shadow-frame vectors.
bool frame_pop_enabled;
// The overall refcount for each internal event across all threads.
std::array<int32_t, kInternalEventCount> internal_event_refcount_ GUARDED_BY(envs_lock_);
// The refcount for each thread for each internal event.
// TODO We should clean both this and the normal EventMask lists up when threads end.
std::array<std::unordered_map<UniqueThread, int32_t, UniqueThreadHasher>, kInternalEventCount>
internal_event_thread_refcount_
GUARDED_BY(envs_lock_) GUARDED_BY(art::Locks::thread_list_lock_);
friend class JvmtiMethodTraceListener;
};
} // namespace openjdkjvmti
#endif // ART_OPENJDKJVMTI_EVENTS_H_
|