/* * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
/////////////////////////////////////////////////////////////// // // JvmtiEventTransition // // TO DO -- // more handle purging
// Use this for JavaThreads and state is _thread_in_vm. class JvmtiJavaThreadEventTransition : StackObj { private:
ResourceMark _rm;
ThreadToNativeFromVM _transition;
HandleMark _hm;
// For JavaThreads which are not in _thread_in_vm state // and other system threads use this. class JvmtiThreadEventTransition : StackObj { private:
ResourceMark _rm;
HandleMark _hm;
JavaThreadState _saved_state;
JavaThread *_jthread;
class JvmtiEventMark : public StackObj { private:
JavaThread *_thread;
JNIEnv* _jni_env;
JvmtiThreadState::ExceptionState _saved_exception_state;
public:
JvmtiEventMark(JavaThread *thread) : _thread(thread),
_jni_env(thread->jni_environment()),
_saved_exception_state(JvmtiThreadState::ES_CLEARED) {
JvmtiThreadState *state = thread->jvmti_thread_state(); // we are before an event. // Save current jvmti thread exception state. if (state != NULL) {
_saved_exception_state = state->get_exception_state();
}
thread->push_jni_handle_block();
assert(thread == JavaThread::current(), "thread must be current!");
thread->frame_anchor()->make_walkable();
};
JvmtiThreadState* state = _thread->jvmti_thread_state(); // we are continuing after an event. if (state != NULL) { // Restore the jvmti thread exception state.
state->restore_exception_state(_saved_exception_state);
}
}
// interpreter generator needs the address of the counter
address JvmtiExport::get_field_access_count_addr() { // We don't grab a lock because we don't want to // serialize field access between all threads. This means that a // thread on another processor can see the wrong count value and // may either miss making a needed call into post_field_access() // or will make an unneeded call into post_field_access(). We pay // this price to avoid slowing down the VM when we aren't watching // field accesses. // Other access/mutation safe by virtue of being in VM state. return (address)(&_field_access_count);
}
// // field modification management //
// interpreter generator needs the address of the counter
address JvmtiExport::get_field_modification_count_addr() { // We don't grab a lock because we don't // want to serialize field modification between all threads. This // means that a thread on another processor can see the wrong // count value and may either miss making a needed call into // post_field_modification() or will make an unneeded call into // post_field_modification(). We pay this price to avoid slowing // down the VM when we aren't watching field modifications. // Other access/mutation safe by virtue of being in VM state. return (address)(&_field_modification_count);
}
/////////////////////////////////////////////////////////////// // Functions needed by java.lang.instrument for starting up javaagent. ///////////////////////////////////////////////////////////////
jint
JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { // The JVMTI_VERSION_INTERFACE_JVMTI part of the version number // has already been validated in JNI GetEnv(). int major, minor, micro;
// micro version doesn't matter here (yet?)
decode_version_values(version, &major, &minor, µ); switch (major) { case 1: switch (minor) { case 0: // version 1.0.<micro> is recognized case 1: // version 1.1.<micro> is recognized case 2: // version 1.2.<micro> is recognized break;
default: return JNI_EVERSION; // unsupported minor version number
} break; case 9: switch (minor) { case 0: // version 9.0.<micro> is recognized break; default: return JNI_EVERSION; // unsupported minor version number
} break; case 11: switch (minor) { case 0: // version 11.0.<micro> is recognized break; default: return JNI_EVERSION; // unsupported minor version number
} break; default: // Starting from 13 we do not care about minor version anymore if (major < 13 || major > VM_Version::vm_major_version()) { return JNI_EVERSION; // unsupported major version number
}
} if (Continuations::enabled()) { // Virtual threads support. There is a performance impact when VTMS transitions are enabled.
java_lang_VirtualThread::set_notify_jvmti_events(true); if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
ThreadInVMfromNative __tiv(JavaThread::current());
java_lang_VirtualThread::init_static_notify_jvmti_events();
}
}
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
JavaThread* current_thread = JavaThread::current(); // transition code: native to VM
ThreadInVMfromNative __tiv(current_thread);
VM_ENTRY_BASE(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread)
debug_only(VMNativeEntryWrapper __vew;)
JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
*penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv* return JNI_OK;
} elseif (JvmtiEnv::get_phase() == JVMTI_PHASE_ONLOAD) { // not live, no thread to transition
JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
*penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv* return JNI_OK;
} else { // Called at the wrong time
*penv = NULL; return JNI_EDETACHED;
}
}
void
JvmtiExport::add_default_read_edges(Handle h_module, TRAPS) { if (!Universe::is_module_initialized()) { return; // extra safety
}
assert(!h_module.is_null(), "module should always be set");
jvmtiError
JvmtiExport::add_module_reads(Handle module, Handle to_module, TRAPS) { if (!Universe::is_module_initialized()) { return JVMTI_ERROR_NONE; // extra safety
}
assert(!module.is_null(), "module should always be set");
assert(!to_module.is_null(), "to_module should always be set");
jvmtiError
JvmtiExport::add_module_exports(Handle module, Handle pkg_name, Handle to_module, TRAPS) { if (!Universe::is_module_initialized()) { return JVMTI_ERROR_NONE; // extra safety
}
assert(!module.is_null(), "module should always be set");
assert(!to_module.is_null(), "to_module should always be set");
assert(!pkg_name.is_null(), "pkg_name should always be set");
jvmtiError
JvmtiExport::add_module_opens(Handle module, Handle pkg_name, Handle to_module, TRAPS) { if (!Universe::is_module_initialized()) { return JVMTI_ERROR_NONE; // extra safety
}
assert(!module.is_null(), "module should always be set");
assert(!to_module.is_null(), "to_module should always be set");
assert(!pkg_name.is_null(), "pkg_name should always be set");
jvmtiError
JvmtiExport::add_module_uses(Handle module, Handle service, TRAPS) { if (!Universe::is_module_initialized()) { return JVMTI_ERROR_NONE; // extra safety
}
assert(!module.is_null(), "module should always be set");
assert(!service.is_null(), "service should always be set");
jvmtiError
JvmtiExport::add_module_provides(Handle module, Handle service, Handle impl_class, TRAPS) { if (!Universe::is_module_initialized()) { return JVMTI_ERROR_NONE; // extra safety
}
assert(!module.is_null(), "module should always be set");
assert(!service.is_null(), "service should always be set");
assert(!impl_class.is_null(), "impl_class should always be set");
// // JVMTI events that the VM posts to the debugger and also startup agent // and call the agent's premain() for java.lang.instrument. //
void JvmtiExport::post_early_vm_start() {
EVT_TRIG_TRACE(JVMTI_EVENT_VM_START, ("Trg Early VM start event triggered" ));
// can now enable some events
JvmtiEventController::vm_start();
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { // Only early vmstart envs post early VMStart event if (env->early_vmstart_env() && env->is_enabled(JVMTI_EVENT_VM_START)) {
EVT_TRACE(JVMTI_EVENT_VM_START, ("Evt Early VM start event sent" ));
JavaThread *thread = JavaThread::current();
JvmtiThreadEventMark jem(thread);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventVMStart callback = env->callbacks()->VMStart; if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env());
}
}
}
}
void JvmtiExport::post_vm_start() {
EVT_TRIG_TRACE(JVMTI_EVENT_VM_START, ("Trg VM start event triggered" ));
// can now enable some events
JvmtiEventController::vm_start();
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { // Early vmstart envs do not post normal VMStart event if (!env->early_vmstart_env() && env->is_enabled(JVMTI_EVENT_VM_START)) {
EVT_TRACE(JVMTI_EVENT_VM_START, ("Evt VM start event sent" ));
void JvmtiExport::initialize_oop_storage() { // OopStorage needs to be created early in startup and unconditionally // because of OopStorageSet static array indices.
_jvmti_oop_storage = OopStorageSet::create_strong("JVMTI OopStorage", mtServiceability);
_weak_tag_storage = OopStorageSet::create_weak("JVMTI Tag Weak OopStorage", mtServiceability);
_weak_tag_storage->register_num_dead_callback(&JvmtiTagMap::gc_notification);
}
void JvmtiExport::post_vm_initialized() {
EVT_TRIG_TRACE(JVMTI_EVENT_VM_INIT, ("Trg VM init event triggered" ));
// can now enable events
JvmtiEventController::vm_init();
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { if (env->is_enabled(JVMTI_EVENT_VM_INIT)) {
EVT_TRACE(JVMTI_EVENT_VM_INIT, ("Evt VM init event sent" ));
char**
JvmtiExport::get_all_native_method_prefixes(int* count_ptr) { // Have to grab JVMTI thread state lock to be sure environment doesn't // go away while we iterate them. No locks during VM bring-up. if (Threads::number_of_threads() == 0 || SafepointSynchronize::is_at_safepoint()) { return JvmtiEnvBase::get_all_native_method_prefixes(count_ptr);
} else {
MutexLocker mu(JvmtiThreadState_lock); return JvmtiEnvBase::get_all_native_method_prefixes(count_ptr);
}
}
// Convert an external thread reference to a JavaThread found on the // specified ThreadsList. The ThreadsListHandle in the caller "protects" // the returned JavaThread *. // // If thread_oop_p is not NULL, then the caller wants to use the oop // after this call so the oop is returned. On success, *jt_pp is set // to the converted JavaThread * and JVMTI_ERROR_NONE is returned. // On error, returns various JVMTI_ERROR_* values. //
jvmtiError
JvmtiExport::cv_external_thread_to_JavaThread(ThreadsList * t_list,
jthread thread,
JavaThread ** jt_pp,
oop * thread_oop_p) {
assert(t_list != NULL, "must have a ThreadsList");
assert(jt_pp != NULL, "must have a return JavaThread pointer"); // thread_oop_p is optional so no assert()
if (thread_oop_p != NULL) {
*thread_oop_p = NULL;
}
oop thread_oop = JNIHandles::resolve_external_guard(thread); if (thread_oop == NULL) { // NULL jthread, GC'ed jthread or a bad JNI handle. return JVMTI_ERROR_INVALID_THREAD;
} // Looks like an oop at this point.
if (!thread_oop->is_a(vmClasses::Thread_klass())) { // The oop is not a java.lang.Thread. return JVMTI_ERROR_INVALID_THREAD;
} // Looks like a java.lang.Thread oop at this point.
if (thread_oop_p != NULL) { // Return the oop to the caller; the caller may still want // the oop even if this function returns an error.
*thread_oop_p = thread_oop;
}
JavaThread * java_thread = java_lang_Thread::thread(thread_oop); if (java_thread == NULL) { if (java_lang_VirtualThread::is_instance(thread_oop)) { return JVMTI_ERROR_INVALID_THREAD;
} // The java.lang.Thread does not contain a JavaThread * so it has // not yet run or it has died. return JVMTI_ERROR_THREAD_NOT_ALIVE;
} // Looks like a live JavaThread at this point.
// We do not check the EnableThreadSMRExtraValidityChecks option // for this includes() call because JVM/TI's spec is tighter. if (!t_list->includes(java_thread)) { // Not on the JavaThreads list so it is not alive. return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Return a live JavaThread that is "protected" by the // ThreadsListHandle in the caller.
*jt_pp = java_thread;
return JVMTI_ERROR_NONE;
}
// Convert an oop to a JavaThread found on the specified ThreadsList. // The ThreadsListHandle in the caller "protects" the returned // JavaThread *. // // On success, *jt_pp is set to the converted JavaThread * and // JVMTI_ERROR_NONE is returned. On error, returns various // JVMTI_ERROR_* values. //
jvmtiError
JvmtiExport::cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop,
JavaThread ** jt_pp) {
assert(t_list != NULL, "must have a ThreadsList");
assert(thread_oop != NULL, "must have an oop");
assert(jt_pp != NULL, "must have a return JavaThread pointer");
if (!thread_oop->is_a(vmClasses::Thread_klass())) { // The oop is not a java.lang.Thread. return JVMTI_ERROR_INVALID_THREAD;
} // Looks like a java.lang.Thread oop at this point.
JavaThread * java_thread = java_lang_Thread::thread(thread_oop); if (java_thread == NULL) { // The java.lang.Thread does not contain a JavaThread * so it has // not yet run or it has died. return JVMTI_ERROR_THREAD_NOT_ALIVE;
} // Looks like a live JavaThread at this point.
// We do not check the EnableThreadSMRExtraValidityChecks option // for this includes() call because JVM/TI's spec is tighter. if (!t_list->includes(java_thread)) { // Not on the JavaThreads list so it is not alive. return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Return a live JavaThread that is "protected" by the // ThreadsListHandle in the caller.
*jt_pp = java_thread;
assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition");
_state = _thread->jvmti_thread_state(); if (_state != NULL) {
_class_being_redefined = _state->get_class_being_redefined();
_load_kind = _state->get_class_load_kind();
Klass* klass = (_class_being_redefined == NULL) ? NULL : _class_being_redefined; if (_load_kind != jvmti_class_load_kind_load && klass != NULL) {
ModuleEntry* module_entry = InstanceKlass::cast(klass)->module();
assert(module_entry != NULL, "module_entry should always be set"); if (module_entry->is_named() &&
module_entry->module() != NULL &&
!module_entry->has_default_read_edges()) { if (!module_entry->set_has_default_read_edges()) { // We won a potential race. // Add read edges to the unnamed modules of the bootstrap and app class loaders
Handle class_module(_thread, module_entry->module()); // Obtain j.l.r.Module
JvmtiExport::add_default_read_edges(class_module, _thread);
}
}
} // Clear class_being_redefined flag here. The action // from agent handler could generate a new class file load // hook event and if it is not cleared the new event generated // from regular class file load could have this stale redefined // class handle info.
_state->clear_class_being_redefined();
} else { // redefine and retransform will always set the thread state
_class_being_redefined = NULL;
_load_kind = jvmti_class_load_kind_load;
}
}
private: void post_all_envs() { if (_load_kind != jvmti_class_load_kind_retransform) { // for class load and redefine, // call the non-retransformable agents
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { if (!env->is_retransformable() && env->is_enabled(JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) { // non-retransformable agents cannot retransform back, // so no need to cache the original class file bytes
post_to_env(env, false);
}
}
}
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { // retransformable agents get all events if (env->is_retransformable() && env->is_enabled(JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) { // retransformable agents need to cache the original class file // bytes if changes are made via the ClassFileLoadHook
post_to_env(env, true);
}
}
}
void post_to_env(JvmtiEnv* env, bool caching_needed) { if (env->phase() == JVMTI_PHASE_PRIMORDIAL && !env->early_class_hook_env()) { return;
} unsignedchar *new_data = NULL;
jint new_len = 0;
JvmtiClassFileLoadEventMark jem(_thread, _h_name, _class_loader,
_h_protection_domain,
_class_being_redefined);
JvmtiJavaThreadEventTransition jet(_thread);
jvmtiEventClassFileLoadHook callback = env->callbacks()->ClassFileLoadHook; if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env(),
jem.class_being_redefined(),
jem.jloader(), jem.class_name(),
jem.protection_domain(),
_curr_len, _curr_data,
&new_len, &new_data);
} if (new_data != NULL) { // this agent has modified class data.
_has_been_modified = true; if (caching_needed && *_cached_class_file_ptr == NULL) { // data has been changed by the new retransformable agent // and it hasn't already been cached, cache it
JvmtiCachedClassFileData *p;
p = (JvmtiCachedClassFileData *)os::malloc(
offset_of(JvmtiCachedClassFileData, data) + _curr_len, mtInternal); if (p == NULL) {
vm_exit_out_of_memory(offset_of(JvmtiCachedClassFileData, data) + _curr_len,
OOM_MALLOC_ERROR, "unable to allocate cached copy of original class bytes");
}
p->length = _curr_len;
memcpy(p->data, _curr_data, _curr_len);
*_cached_class_file_ptr = p;
}
if (_curr_data != *_data_ptr) { // curr_data is previous agent modified class data. // And this has been changed by the new agent so // we can delete it now.
_curr_env->Deallocate(_curr_data);
}
// Class file data has changed by the current agent.
_curr_data = new_data;
_curr_len = new_len; // Save the current agent env we need this to deallocate the // memory allocated by this agent.
_curr_env = env;
}
}
void copy_modified_data() { // if one of the agent has modified class file data. // Copy modified class data to new resources array. if (_curr_data != *_data_ptr) {
*_data_ptr = NEW_RESOURCE_ARRAY(u1, _curr_len);
memcpy(*_data_ptr, _curr_data, _curr_len);
*_end_ptr = *_data_ptr + _curr_len;
_curr_env->Deallocate(_curr_data);
}
}
};
// this entry is for class file load hook on class load, redefine and retransform bool JvmtiExport::post_class_file_load_hook(Symbol* h_name,
Handle class_loader,
Handle h_protection_domain, unsignedchar **data_ptr, unsignedchar **end_ptr,
JvmtiCachedClassFileData **cache_ptr) { if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { returnfalse;
} if (JavaThread::current()->is_in_tmp_VTMS_transition()) { returnfalse; // skip CFLH events in tmp VTMS transition
}
void JvmtiExport::report_unsupported(bool on) { // If any JVMTI service is turned on, we need to exit before native code // tries to access nonexistent services. if (on) {
vm_exit_during_initialization("Java Kernel does not support JVMTI.");
}
}
staticinline Klass* oop_to_klass(oop obj) {
Klass* k = obj->klass();
// if the object is a java.lang.Class then return the java mirror if (k == vmClasses::Class_klass()) { if (!java_lang_Class::is_primitive(obj)) {
k = java_lang_Class::as_Klass(obj);
assert(k != NULL, "class for non-primitive mirror must exist");
}
} return k;
}
// post the event for each environment that has this event enabled.
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_UNLOAD)) { if (env->phase() == JVMTI_PHASE_PRIMORDIAL) { continue;
}
EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
("[%s] class compile method unload event sent jmethodID " PTR_FORMAT,
JvmtiTrace::safe_get_thread_name(thread), p2i(method)));
JvmtiThreadState *state = thread->jvmti_thread_state(); if (state == NULL) { return;
} if (thread->is_in_any_VTMS_transition()) { return; // no events should be posted if thread is in any VTMS transition
}
// update information about current location and post a step event
JvmtiThreadState *state = thread->jvmti_thread_state(); if (state == NULL) { return;
}
EVT_TRIG_TRACE(JVMTI_EVENT_SINGLE_STEP, ("[%s] Trg Single Step triggered",
JvmtiTrace::safe_get_thread_name(thread))); if (!state->hide_single_stepping()) { if (state->is_pending_step_for_popframe()) {
state->process_pending_step_for_popframe();
} if (state->is_pending_step_for_earlyret()) {
state->process_pending_step_for_earlyret();
}
JvmtiExport::post_single_step(thread, mh(), location);
}
}
JvmtiThreadState* state = thread->jvmti_thread_state(); if (state == NULL) { return;
} if (thread->is_in_tmp_VTMS_transition()) { return; // skip ClassLoad events in tmp VTMS transition
}
assert(!thread->is_in_any_VTMS_transition(), "class load events are not allowed in any VTMS transition");
EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Trg Class Load triggered",
JvmtiTrace::safe_get_thread_name(thread)));
JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_CLASS_LOAD)) {
JvmtiEnv *env = ets->get_env(); if (env->phase() == JVMTI_PHASE_PRIMORDIAL) { continue;
}
EVT_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Evt Class Load sent %s",
JvmtiTrace::safe_get_thread_name(thread),
klass==NULL? "NULL" : klass->external_name() ));
JvmtiClassEventMark jem(thread, klass);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventClassLoad callback = env->callbacks()->ClassLoad; if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread(), jem.jni_class());
}
}
}
}
JvmtiThreadState* state = thread->jvmti_thread_state(); if (state == NULL) { return;
} if (thread->is_in_tmp_VTMS_transition()) { return; // skip ClassPrepare events in tmp VTMS transition
}
assert(!thread->is_in_any_VTMS_transition(), "class prepare events are not allowed in any VTMS transition");
EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Trg Class Prepare triggered",
JvmtiTrace::safe_get_thread_name(thread)));
JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_CLASS_PREPARE)) {
JvmtiEnv *env = ets->get_env(); if (env->phase() == JVMTI_PHASE_PRIMORDIAL) { continue;
}
EVT_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Evt Class Prepare sent %s",
JvmtiTrace::safe_get_thread_name(thread),
klass==NULL? "NULL" : klass->external_name() ));
JvmtiClassEventMark jem(thread, klass);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventClassPrepare callback = env->callbacks()->ClassPrepare; if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread(), jem.jni_class());
}
}
}
}
// postings to the service thread so that it can perform them in a safe // context and in-order.
ResourceMark rm; // JvmtiDeferredEvent copies the string.
JvmtiDeferredEvent event = JvmtiDeferredEvent::class_unload_event(klass->name()->as_C_string());
ServiceThread::enqueue_deferred_event(&event);
}
void JvmtiExport::post_class_unload_internal(constchar* name) { if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return;
}
assert(Thread::current()->is_service_thread(), "must be called from ServiceThread");
JavaThread *thread = JavaThread::current();
HandleMark hm(thread);
EVT_TRIG_TRACE(EXT_EVENT_CLASS_UNLOAD, ("[?] Trg Class Unload triggered" )); if (JvmtiEventController::is_enabled((jvmtiEvent)EXT_EVENT_CLASS_UNLOAD)) {
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { if (env->phase() == JVMTI_PHASE_PRIMORDIAL) { continue;
} if (env->is_enabled((jvmtiEvent)EXT_EVENT_CLASS_UNLOAD)) {
EVT_TRACE(EXT_EVENT_CLASS_UNLOAD, ("[?] Evt Class Unload sent %s", name));
void JvmtiExport::post_thread_start(JavaThread *thread) { if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return;
}
assert(thread->thread_state() == _thread_in_vm, "must be in vm state");
EVT_TRIG_TRACE(JVMTI_EVENT_THREAD_START, ("[%s] Trg Thread Start event triggered",
JvmtiTrace::safe_get_thread_name(thread)));
// do JVMTI thread initialization (if needed)
JvmtiEventController::thread_started(thread);
// Do not post thread start event for hidden java thread. if (JvmtiEventController::is_enabled(JVMTI_EVENT_THREAD_START) &&
!thread->is_hidden_from_external_view()) {
JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { if (env->phase() == JVMTI_PHASE_PRIMORDIAL) { continue;
} if (env->is_enabled(JVMTI_EVENT_THREAD_START)) {
EVT_TRACE(JVMTI_EVENT_THREAD_START, ("[%s] Evt Thread Start event sent",
JvmtiTrace::safe_get_thread_name(thread) ));
// Clear frame_pop requests in frames popped by yield if (can_post_frame_pop()) {
JvmtiEnvThreadStateIterator it(state); int top_frame_num = state->cur_stack_depth() + continuation_frame_count;
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (!ets->has_frame_pops()) { continue;
} for (int frame_idx = 0; frame_idx < continuation_frame_count; frame_idx++) { int frame_num = top_frame_num - frame_idx;
if (!state->is_virtual() && ets->is_frame_pop(frame_num)) { // remove the frame's entry
MutexLocker mu(JvmtiThreadState_lock);
ets->clear_frame_pop(frame_num);
}
}
}
}
}
JavaThread *javaThread = JavaThread::current(); if (javaThread->is_in_any_VTMS_transition()) { return; // no events should be posted if thread is in any VTMS transition
} if (!env->is_enabled(JVMTI_EVENT_OBJECT_FREE)) { return; // the event type has been already disabled
}
// JDK-8213834: handlers of ResourceExhausted may attempt some analysis // which often requires running java. // This will cause problems on threads not able to run java, e.g. compiler // threads. To forestall these problems, we therefore suppress sending this // event from threads which are not able to run java. if (!thread->can_call_java()) { return;
}
JvmtiThreadState* state = thread->jvmti_thread_state(); if (state == NULL || !state->is_interp_only_mode()) { // for any thread that actually wants method entry, interp_only_mode is set return;
} if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { return; // no events should be posted if thread is in any VTMS transition
}
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_ENTRY, ("[%s] Trg Method Entry triggered %s.%s",
JvmtiTrace::safe_get_thread_name(thread),
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
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.