// Helper for ensuring that the dispatch environment is suitably provisioned. Events with JNIEnvs // need to stash pending exceptions since they can cause new ones to be thrown. In accordance with // the JVMTI specification we allow exceptions originating from events to overwrite the current // exception, including exceptions originating from earlier events. class ScopedEventDispatchEnvironment final : public art::ValueObject { public:
ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) {
DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
}
explicit ScopedEventDispatchEnvironment(JNIEnv* env)
: env_(env),
throw_(env_, env_->ExceptionOccurred()) {
DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative); // The spec doesn't say how much local data should be there, so we just give 128 which seems // likely to be enough for most cases.
env_->PushLocalFrame(128);
env_->ExceptionClear();
}
~ScopedEventDispatchEnvironment() { if (env_ != nullptr) { if (throw_.get() != nullptr && !env_->ExceptionCheck()) { // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list // of the newest exception.
env_->Throw(throw_.get());
}
env_->PopLocalFrame(nullptr);
}
DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative);
}
// C++ does not allow partial template function specialization. The dispatch for our separated // ClassFileLoadHook event types is the same, so use this helper for code deduplication. template <ArtJvmtiEvent kEvent> inlinevoid EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
JNIEnv* jnienv,
jclass class_being_redefined,
jobject loader, constchar* name,
jobject protection_domain,
jint class_data_len, constunsignedchar* class_data,
jint* new_class_data_len, unsignedchar** new_class_data) const {
art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
kEvent == ArtJvmtiEvent::kStructuralDexFileLoadHook, "Unsupported event");
DCHECK(*new_class_data == nullptr);
jint current_len = class_data_len; unsignedchar* current_class_data = const_cast<unsignedchar*>(class_data);
std::vector<impl::EventHandlerFunc<kEvent>> handlers =
CollectEvents<kEvent>(thread,
jnienv,
class_being_redefined,
loader,
name,
protection_domain,
class_data_len,
class_data,
new_class_data_len,
new_class_data);
ArtJvmTiEnv* last_env = nullptr; for (const impl::EventHandlerFunc<kEvent>& event : handlers) {
jint new_len = 0; unsignedchar* new_data = nullptr;
ExecuteCallback<kEvent>(event,
jnienv,
class_being_redefined,
loader,
name,
protection_domain,
current_len, static_cast<constunsignedchar*>(current_class_data),
&new_len,
&new_data); if (new_data != nullptr && new_data != current_class_data) { // Destroy the data the last transformer made. We skip this if the previous state was the // initial one since we don't know here which jvmtiEnv allocated it. // NB Currently this doesn't matter since all allocations just go to malloc but in the // future we might have jvmtiEnv's keep track of their allocations for leak-checking. if (last_env != nullptr) {
last_env->Deallocate(current_class_data);
}
last_env = event.env_;
current_class_data = new_data;
current_len = new_len;
}
} if (last_env != nullptr) {
*new_class_data_len = current_len;
*new_class_data = current_class_data;
}
}
// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match // exactly the argument types of the corresponding Jvmti kEvent function pointer.
// Events that need custom logic for if we send the event but are otherwise normal. This includes // the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events.
// Need to give custom specializations for Breakpoint since it needs to filter out which particular // methods/dex_pcs agents get notified on. template <> inlinebool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
ArtJvmTiEnv* env,
art::Thread* thread,
template <> inlinebool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
ArtJvmTiEnv* env,
art::Thread* thread,
[[maybe_unused]] JNIEnv* jnienv,
[[maybe_unused]] jthread jni_thread,
[[maybe_unused]] jmethodID jmethod,
[[maybe_unused]] jboolean is_exception, const art::ShadowFrame* frame) const { // Search for the frame. Do this before checking if we need to send the event so that we don't // have to deal with use-after-free or the frames being reallocated later.
art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_); return env->notify_frames.erase(frame) != 0 &&
!frame->GetSkipMethodExitEvents() &&
ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
}
// Need to give custom specializations for FieldAccess and FieldModification since they need to // filter out which particular fields agents want to get notified on. // TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This // could make the system more performant. template <> inlinebool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
ArtJvmTiEnv* env,
art::Thread* thread,
[[maybe_unused]] JNIEnv* jnienv,
[[maybe_unused]] jthread jni_thread,
[[maybe_unused]] jmethodID method,
[[maybe_unused]] jlocation location,
[[maybe_unused]] jclass field_klass,
[[maybe_unused]] jobject object,
jfieldID field,
[[maybe_unused]] char type_char,
[[maybe_unused]] jvalue val) const {
art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_); return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
env->modify_watched_fields.find(field) != env->modify_watched_fields.end();
}
// Need to give custom specializations for FramePop since it needs to filter out which particular // agents get the event. This specialization gets an extra argument so we can determine which (if // any) environments have the frame pop. // TODO It might be useful to use more template magic to have this only define ShouldDispatch or // something. template <> inlinevoid EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>(
impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event,
JNIEnv* jnienv,
jthread jni_thread,
jmethodID jmethod,
jboolean is_exception,
[[maybe_unused]] const art::ShadowFrame* frame) {
ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
}
struct ScopedDisablePopFrame { public: explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) {
art::Locks::mutator_lock_->AssertSharedHeld(thread_);
art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_);
current_top_frame_ = art::StackVisitor::ComputeNumFrames(
thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
data->disable_pop_frame_depth = current_top_frame_; // Check that we cleaned up any old disables. This should only increase (or be equals if we do // another ClassLoad/Prepare recursively).
DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
current_top_frame_ >= old_disable_frame_pop_depth_)
<< "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
}
// Need to give a custom specialization for NativeMethodBind since it has to deal with an out // variable. template <> inlinevoid EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
JNIEnv* jnienv,
jthread jni_thread,
jmethodID method, void* cur_method, void** new_method) const {
art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events =
CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread,
jnienv,
jni_thread,
method,
cur_method,
new_method);
*new_method = cur_method; for (auto event : events) {
*new_method = cur_method;
ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event,
jnienv,
jni_thread,
method,
cur_method,
new_method); if (*new_method != nullptr) {
cur_method = *new_method;
}
}
*new_method = cur_method;
}
// C++ does not allow partial template function specialization. The dispatch for our separated // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper. // The following two DispatchEvent specializations dispatch to it. template <> inlinevoid EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
art::Thread* thread,
JNIEnv* jnienv,
jclass class_being_redefined,
jobject loader, constchar* name,
jobject protection_domain,
jint class_data_len, constunsignedchar* class_data,
jint* new_class_data_len, unsignedchar** new_class_data) const { return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
thread,
jnienv,
class_being_redefined,
loader,
name,
protection_domain,
class_data_len,
class_data,
new_class_data_len,
new_class_data);
}
inlinevoid 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);
} if (added && caps.can_access_local_variables == 1) {
HandleLocalAccessCapabilityAdded();
} if (caps.can_generate_breakpoint_events == 1) {
HandleBreakpointEventsChanged(added);
} if ((caps.can_pop_frame == 1 || caps.can_force_early_return == 1) && added) { // TODO We should keep track of how many of these have been enabled and remove it if there are // no more possible users. This isn't expected to be too common.
art::Runtime::Current()->SetNonStandardExitsEnabled();
}
}
}
} // namespace openjdkjvmti
#endif// ART_OPENJDKJVMTI_EVENTS_INL_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.