/* * 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. *
*/
// VM operation class to copy jni function table at safepoint. // More than one java threads or jvmti agents may be reading/ // modifying jni function tables. To reduce the risk of bad // interaction b/w these threads it is copied at safepoint. class VM_JNIFunctionTableCopier : public VM_Operation { private: conststruct JNINativeInterface_ *_function_table; public:
VM_JNIFunctionTableCopier(conststruct JNINativeInterface_ *func_tbl) {
_function_table = func_tbl;
};
// // Do not change the "prefix" marker below, everything above it is copied // unchanged into the filled stub, everything below is controlled by the // stub filler (only method bodies are carried forward, and then only for // functionality still in the spec). // // end file prefix
// // Memory Management functions //
// mem_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::Allocate(jlong size, unsignedchar** mem_ptr) { return allocate(size, mem_ptr);
} /* end Allocate */
// mem - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::Deallocate(unsignedchar* mem) { return deallocate(mem);
} /* end Deallocate */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // data - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::SetThreadLocalStorage(jthread thread, constvoid* data) {
JavaThread* current = JavaThread::current();
JvmtiThreadState* state = NULL;
JvmtiVTMSTransitionDisabler disabler;
ThreadsListHandle tlh(current);
JavaThread* java_thread = NULL;
oop thread_obj = NULL; if (thread == NULL) {
java_thread = current;
state = java_thread->jvmti_thread_state();
} else {
jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj); if (err != JVMTI_ERROR_NONE) { return err;
}
state = java_lang_Thread::jvmti_thread_state(thread_obj);
} if (state == NULL) { if (data == NULL) { // leaving state unset same as data set to NULL return JVMTI_ERROR_NONE;
} // otherwise, create the state
HandleMark hm(current);
Handle thread_handle(current, thread_obj);
state = JvmtiThreadState::state_for(java_thread, thread_handle); if (state == NULL) { return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
state->env_thread_state(this)->set_agent_thread_local_storage_data((void*)data); return JVMTI_ERROR_NONE;
} /* end SetThreadLocalStorage */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // data_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
JavaThread* current_thread = JavaThread::current(); if (thread == NULL) {
JvmtiThreadState* state = current_thread->jvmti_thread_state();
*data_ptr = (state == NULL) ? NULL :
state->env_thread_state(this)->get_agent_thread_local_storage_data();
} else { // jvmti_GetThreadLocalStorage is "in native" and doesn't transition // the thread to _thread_in_vm. However, when the TLS for a thread // other than the current thread is required we need to transition // from native so as to resolve the jthread.
*is_modifiable_module_ptr = JNI_TRUE; return JVMTI_ERROR_NONE;
} /* end IsModifiableModule */
// // Class functions //
// class_count_ptr - pre-checked for NULL // classes_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetLoadedClasses(jint* class_count_ptr, jclass** classes_ptr) { return JvmtiGetLoadedClasses::getLoadedClasses(this, class_count_ptr, classes_ptr);
} /* end GetLoadedClasses */
// initiating_loader - NULL is a valid value, must be checked // class_count_ptr - pre-checked for NULL // classes_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetClassLoaderClasses(jobject initiating_loader, jint* class_count_ptr, jclass** classes_ptr) { return JvmtiGetLoadedClasses::getClassLoaderClasses(this, initiating_loader,
class_count_ptr, classes_ptr);
} /* end GetClassLoaderClasses */
// k_mirror - may be primitive, this must be checked // is_modifiable_class_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::IsModifiableClass(oop k_mirror, jboolean* is_modifiable_class_ptr) {
*is_modifiable_class_ptr = VM_RedefineClasses::is_modifiable_class(k_mirror)?
JNI_TRUE : JNI_FALSE; return JVMTI_ERROR_NONE;
} /* end IsModifiableClass */
// class_count - pre-checked to be greater than or equal to 0 // classes - pre-checked for NULL
jvmtiError
JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) { //TODO: add locking
int index;
JavaThread* current_thread = JavaThread::current();
ResourceMark rm(current_thread);
if (!VM_RedefineClasses::is_modifiable_class(k_mirror)) { return JVMTI_ERROR_UNMODIFIABLE_CLASS;
}
Klass* klass = java_lang_Class::as_Klass(k_mirror);
jint status = klass->jvmti_class_status(); if (status & (JVMTI_CLASS_STATUS_ERROR)) { return JVMTI_ERROR_INVALID_CLASS;
}
InstanceKlass* ik = InstanceKlass::cast(klass); if (ik->get_cached_class_file_bytes() == NULL) { // Not cached, we need to reconstitute the class file from the // VM representation. We don't attach the reconstituted class // bytes to the InstanceKlass here because they have not been // validated and we're not at a safepoint.
JvmtiClassFileReconstituter reconstituter(ik); if (reconstituter.get_error() != JVMTI_ERROR_NONE) { return reconstituter.get_error();
}
class_definitions[index].class_byte_count = (jint)reconstituter.class_file_size();
class_definitions[index].class_bytes = (unsignedchar*)
reconstituter.class_file_bytes();
} else { // it is cached, get it from the cache
class_definitions[index].class_byte_count = ik->get_cached_class_file_len();
class_definitions[index].class_bytes = ik->get_cached_class_file_bytes();
}
class_definitions[index].klass = jcls;
}
EventRetransformClasses event;
VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform);
VMThread::execute(&op);
jvmtiError error = op.check_error(); if (error == JVMTI_ERROR_NONE) {
event.set_classCount(class_count);
event.set_redefinitionId(op.id());
event.commit();
} return error;
} /* end RetransformClasses */
// class_count - pre-checked to be greater than or equal to 0 // class_definitions - pre-checked for NULL
jvmtiError
JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) { //TODO: add locking
EventRedefineClasses event;
VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine);
VMThread::execute(&op);
jvmtiError error = op.check_error(); if (error == JVMTI_ERROR_NONE) {
event.set_classCount(class_count);
event.set_redefinitionId(op.id());
event.commit();
} return error;
} /* end RedefineClasses */
// prefix - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::SetNativeMethodPrefix(constchar* prefix) { return prefix == NULL?
SetNativeMethodPrefixes(0, NULL) :
SetNativeMethodPrefixes(1, (char**)&prefix);
} /* end SetNativeMethodPrefix */
// prefix_count - pre-checked to be greater than or equal to 0 // prefixes - pre-checked for NULL
jvmtiError
JvmtiEnv::SetNativeMethodPrefixes(jint prefix_count, char** prefixes) { // Have to grab JVMTI thread state lock to be sure that some thread // isn't accessing the prefixes at the same time we are setting them. // No locks during VM bring-up. if (Threads::number_of_threads() == 0) { return set_native_method_prefixes(prefix_count, prefixes);
} else {
MutexLocker mu(JvmtiThreadState_lock); return set_native_method_prefixes(prefix_count, prefixes);
}
} /* end SetNativeMethodPrefixes */
// // Event Management functions //
// callbacks - NULL is a valid value, must be checked // size_of_callbacks - pre-checked to be greater than or equal to 0
jvmtiError
JvmtiEnv::SetEventCallbacks(const jvmtiEventCallbacks* callbacks, jint size_of_callbacks) {
JvmtiVTMSTransitionDisabler disabler;
JvmtiEventController::set_event_callbacks(this, callbacks, size_of_callbacks); return JVMTI_ERROR_NONE;
} /* end SetEventCallbacks */
// event_thread - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread, ...) { bool enabled = (mode == JVMTI_ENABLE);
// event_type must be valid if (!JvmtiEventController::is_valid_event_type(event_type)) { return JVMTI_ERROR_INVALID_EVENT_TYPE;
}
// assure that needed capabilities are present if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
}
if (event_thread == NULL) { // Can be called at Agent_OnLoad() time with event_thread == NULL // when Thread::current() does not work yet so we cannot create a // ThreadsListHandle that is common to both thread-specific and // global code paths.
JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, (oop) NULL, event_type, enabled);
} else { // We have a specified event_thread.
ThreadsListHandle tlh;
// capabilities_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetCapabilities(jvmtiCapabilities* capabilities_ptr) {
JvmtiManageCapabilities::copy_capabilities(get_capabilities(), capabilities_ptr); return JVMTI_ERROR_NONE;
} /* end GetCapabilities */
// // Class Loader Search functions //
// segment - pre-checked for NULL
jvmtiError
JvmtiEnv::AddToBootstrapClassLoaderSearch(constchar* segment) {
jvmtiPhase phase = get_phase(); if (phase == JVMTI_PHASE_ONLOAD) {
Arguments::append_sysclasspath(segment); return JVMTI_ERROR_NONE;
} elseif (use_version_1_0_semantics()) { // This JvmtiEnv requested version 1.0 semantics and this function // is only allowed in the ONLOAD phase in version 1.0 so we need to // return an error here. return JVMTI_ERROR_WRONG_PHASE;
} elseif (phase == JVMTI_PHASE_LIVE) { // The phase is checked by the wrapper that called this function, // but this thread could be racing with the thread that is // terminating the VM so we check one more time.
// create the zip entry
ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment, true); if (zip_entry == NULL) { return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
// add the jar file to the bootclasspath
log_info(class, load)("opened: %s", zip_entry->name()); #if INCLUDE_CDS
ClassLoaderExt::append_boot_classpath(zip_entry); #else
ClassLoader::add_to_boot_append_entries(zip_entry); #endif return JVMTI_ERROR_NONE;
} else { return JVMTI_ERROR_WRONG_PHASE;
}
if (phase == JVMTI_PHASE_ONLOAD) { for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) { if (strcmp("java.class.path", p->key()) == 0) {
p->append_value(segment); break;
}
} return JVMTI_ERROR_NONE;
} elseif (phase == JVMTI_PHASE_LIVE) { // The phase is checked by the wrapper that called this function, // but this thread could be racing with the thread that is // terminating the VM so we check one more time.
JavaThread* THREAD = JavaThread::current(); // For exception macros.
HandleMark hm(THREAD);
// create the zip entry (which will open the zip file and hence // check that the segment is indeed a zip file).
ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment, false); if (zip_entry == NULL) { return JVMTI_ERROR_ILLEGAL_ARGUMENT;
} delete zip_entry; // no longer needed
// need the path as java.lang.String
Handle path = java_lang_String::create_from_platform_dependent_str(segment, THREAD); if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; return JVMTI_ERROR_INTERNAL;
}
// Invoke the appendToClassPathForInstrumentation method - if the method // is not found it means the loader doesn't support adding to the class path // in the live phase.
{
JavaValue res(T_VOID);
JavaCalls::call_special(&res,
loader,
loader->klass(),
vmSymbols::appendToClassPathForInstrumentation_name(),
vmSymbols::appendToClassPathForInstrumentation_signature(),
path,
THREAD); if (HAS_PENDING_EXCEPTION) {
Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
CLEAR_PENDING_EXCEPTION;
// data - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::SetEnvironmentLocalStorage(constvoid* data) {
set_env_local_storage(data); return JVMTI_ERROR_NONE;
} /* end SetEnvironmentLocalStorage */
// data_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetEnvironmentLocalStorage(void** data_ptr) {
*data_ptr = (void*)get_env_local_storage(); return JVMTI_ERROR_NONE;
} /* end GetEnvironmentLocalStorage */
// version_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetVersionNumber(jint* version_ptr) {
*version_ptr = JVMTI_VERSION; return JVMTI_ERROR_NONE;
} /* end GetVersionNumber */
jvmtiError
JvmtiEnv::SetVerboseFlag(jvmtiVerboseFlag flag, jboolean value) {
LogLevelType level = value == 0 ? LogLevel::Off : LogLevel::Info; switch (flag) { case JVMTI_VERBOSE_OTHER: // ignore break; case JVMTI_VERBOSE_CLASS:
LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, unload));
LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, load)); break; case JVMTI_VERBOSE_GC:
LogConfiguration::configure_stdout(level, true, LOG_TAGS(gc)); break; case JVMTI_VERBOSE_JNI:
level = value == 0 ? LogLevel::Off : LogLevel::Debug;
LogConfiguration::configure_stdout(level, true, LOG_TAGS(jni, resolve)); break; default: return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}; return JVMTI_ERROR_NONE;
} /* end SetVerboseFlag */
// format_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) {
*format_ptr = JVMTI_JLOCATION_JVMBCI; return JVMTI_ERROR_NONE;
} /* end GetJLocationFormat */
// // Thread functions //
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // thread_state_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
JavaThread* current_thread = JavaThread::current();
JvmtiVTMSTransitionDisabler disabler;
ThreadsListHandle tlh(current_thread);
JavaThread* java_thread = NULL;
oop thread_oop = NULL;
jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_oop); if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_THREAD_NOT_ALIVE) { // We got an error code so we don't have a JavaThread*, but only // return an error from here if the error is not because the thread // is a virtual thread. return err;
}
*threads_ptr = jthreads; return JVMTI_ERROR_NONE;
} /* end GetAllThreads */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked
jvmtiError
JvmtiEnv::SuspendThread(jthread thread) {
JavaThread* current = JavaThread::current();
// Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. if (java_thread != current) {
err = suspend_thread(thread_oop, java_thread, /* single_suspend */ true, NULL); return err;
}
} // Do self suspend for current JavaThread.
err = suspend_thread(thread_oop, current, /* single_suspend */ true, NULL); return err;
} /* end SuspendThread */
// request_count - pre-checked to be greater than or equal to 0 // request_list - pre-checked for NULL // results - pre-checked for NULL
jvmtiError
JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
JavaThread* current = JavaThread::current();
HandleMark hm(current);
Handle self_tobj = Handle(current, NULL); int self_idx = -1;
for (int i = 0; i < request_count; i++) {
JavaThread *java_thread = NULL;
oop thread_oop = NULL;
jthread thread = request_list[i];
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
if (thread_oop != NULL &&
java_lang_VirtualThread::is_instance(thread_oop) &&
!JvmtiEnvBase::is_vthread_alive(thread_oop)) {
err = JVMTI_ERROR_THREAD_NOT_ALIVE;
} if (err != JVMTI_ERROR_NONE) { if (thread_oop == NULL || err != JVMTI_ERROR_INVALID_THREAD) {
results[i] = err; continue;
}
} if (java_thread == current) {
self_idx = i;
self_tobj = Handle(current, thread_oop); continue; // self suspend after all other suspends
}
results[i] = suspend_thread(thread_oop, java_thread, /* single_suspend */ true, NULL);
}
} // Self suspend after all other suspends if necessary. // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != NULL) { // there should not be any error for current java_thread
results[self_idx] = suspend_thread(self_tobj(), current, /* single_suspend */ true, NULL);
} // per-thread suspend results returned via results parameter return JVMTI_ERROR_NONE;
} /* end SuspendThreadList */
jvmtiError
JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list) { if (!JvmtiExport::can_support_virtual_threads()) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
} if (!Continuations::enabled()) { return JVMTI_ERROR_NONE; // Nothing to do when there are no virtual threads;
}
JavaThread* current = JavaThread::current();
HandleMark hm(current);
Handle self_tobj = Handle(current, NULL);
// Collect threads from except_list for which resumed status must be restored. for (int idx = 0; idx < except_count; idx++) {
jthread thread = except_list[idx];
oop thread_oop = JNIHandles::resolve_external_guard(thread); if (!JvmtiVTSuspender::is_vthread_suspended(thread_oop)) { // is not suspended, so its resumed status must be restored
elist->append(except_list[idx]);
}
}
// Restore resumed state for threads from except list that were not suspended before. for (int idx = 0; idx < elist->length(); idx++) {
jthread thread = elist->at(idx);
oop thread_oop = JNIHandles::resolve_external_guard(thread); if (JvmtiVTSuspender::is_vthread_suspended(thread_oop)) {
JvmtiVTSuspender::register_vthread_resume(thread_oop);
}
}
} // Self suspend after all other suspends if necessary. // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != NULL) {
suspend_thread(self_tobj(), current, /* single_suspend */ false, NULL);
} return JVMTI_ERROR_NONE;
} /* end SuspendAllVirtualThreads */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked
jvmtiError
JvmtiEnv::ResumeThread(jthread thread) {
JvmtiVTMSTransitionDisabler disabler(true);
ThreadsListHandle tlh;
// request_count - pre-checked to be greater than or equal to 0 // request_list - pre-checked for NULL // results - pre-checked for NULL
jvmtiError
JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
oop thread_oop = NULL;
JavaThread* java_thread = NULL;
JvmtiVTMSTransitionDisabler disabler(true);
ThreadsListHandle tlh;
for (int i = 0; i < request_count; i++) {
jthread thread = request_list[i];
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
if (thread_oop != NULL &&
java_lang_VirtualThread::is_instance(thread_oop) &&
!JvmtiEnvBase::is_vthread_alive(thread_oop)) {
err = JVMTI_ERROR_THREAD_NOT_ALIVE;
} if (err != JVMTI_ERROR_NONE) { if (thread_oop == NULL || err != JVMTI_ERROR_INVALID_THREAD) {
results[i] = err; continue;
}
}
results[i] = resume_thread(thread_oop, java_thread, /* single_resume */ true);
} // per-thread resume results returned via results parameter return JVMTI_ERROR_NONE;
} /* end ResumeThreadList */
jvmtiError
JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) { if (!JvmtiExport::can_support_virtual_threads()) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
} if (!Continuations::enabled()) { return JVMTI_ERROR_NONE; // Nothing to do when there are no virtual threads;
}
jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list); if (err != JVMTI_ERROR_NONE) { return err;
}
ResourceMark rm;
JvmtiVTMSTransitionDisabler disabler(true);
GrowableArray<jthread>* elist = new GrowableArray<jthread>(except_count);
// Collect threads from except_list for which suspended status must be restored. for (int idx = 0; idx < except_count; idx++) {
jthread thread = except_list[idx];
oop thread_oop = JNIHandles::resolve_external_guard(thread); if (JvmtiVTSuspender::is_vthread_suspended(thread_oop)) { // is suspended, so its suspended status must be restored
elist->append(except_list[idx]);
}
}
// Restore suspended state for threads from except list that were suspended before. for (int idx = 0; idx < elist->length(); idx++) {
jthread thread = elist->at(idx);
oop thread_oop = JNIHandles::resolve_external_guard(thread); if (!JvmtiVTSuspender::is_vthread_suspended(thread_oop)) {
JvmtiVTSuspender::register_vthread_suspend(thread_oop);
}
} return JVMTI_ERROR_NONE;
} /* end ResumeAllVirtualThreads */
if (thread_oop != NULL && java_lang_VirtualThread::is_instance(thread_oop)) { // No support for virtual threads (yet). return JVMTI_ERROR_UNSUPPORTED_OPERATION;
} if (err != JVMTI_ERROR_NONE) { return err;
}
oop e = JNIHandles::resolve_external_guard(exception);
NULL_CHECK(e, JVMTI_ERROR_NULL_POINTER);
JavaThread::send_async_exception(java_thread, e);
return JVMTI_ERROR_NONE;
} /* end StopThread */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked
jvmtiError
JvmtiEnv::InterruptThread(jthread thread) {
JavaThread* current_thread = JavaThread::current();
HandleMark hm(current_thread);
if (java_lang_VirtualThread::is_instance(thread_obj)) { // For virtual threads we have to call into Java to interrupt:
Handle obj(current_thread, thread_obj);
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
obj,
vmClasses::Thread_klass(),
vmSymbols::interrupt_method_name(),
vmSymbols::void_method_signature(),
current_thread);
return JVMTI_ERROR_NONE;
}
// Really this should be a Java call to Thread.interrupt to ensure the same // semantics, however historically this has not been done for some reason. // So we continue with that (which means we don't interact with any Java-level // Interruptible object) but we must set the Java-level interrupted state.
java_lang_Thread::set_interrupted(thread_obj, true);
java_thread->interrupt();
return JVMTI_ERROR_NONE;
} /* end InterruptThread */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // info_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
JavaThread* current_thread = JavaThread::current();
ResourceMark rm(current_thread);
HandleMark hm(current_thread);
JavaThread* java_thread = NULL;
oop thread_oop = NULL;
// if thread is NULL the current thread is used if (thread == NULL) {
java_thread = JavaThread::current();
thread_oop = get_vthread_or_thread_oop(java_thread); if (thread_oop == NULL || !thread_oop->is_a(vmClasses::Thread_klass())) { return JVMTI_ERROR_INVALID_THREAD;
}
} else {
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop); if (err != JVMTI_ERROR_NONE) { // We got an error code so we don't have a JavaThread *, but // only return an error from here if we didn't get a valid // thread_oop. // In the virtual thread case the cv_external_thread_to_JavaThread is expected to correctly set // the thread_oop and return JVMTI_ERROR_INVALID_THREAD which we ignore here. if (thread_oop == NULL) { return err;
}
}
} // We have a valid thread_oop so we can return some thread info.
oop loader = java_lang_Thread::context_class_loader(thread_obj()); if (loader != NULL) { // Do the same as Thread.getContextClassLoader and set context_class_loader to be // the system class loader when the field value is the "not supported" placeholder. if (loader == java_lang_Thread_Constants::get_NOT_SUPPORTED_CLASSLOADER()) {
loader = SystemDictionary::java_system_loader();
}
}
context_class_loader = Handle(current_thread, loader);
{ constchar *n;
if (name() != NULL) {
n = java_lang_String::as_utf8_string(name());
} else { int utf8_length = 0;
n = UNICODE::as_utf8((jchar*) NULL, utf8_length);
}
return JVMTI_ERROR_NONE;
} /* end GetThreadInfo */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // owned_monitor_count_ptr - pre-checked for NULL // owned_monitors_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) {
JavaThread* calling_thread = JavaThread::current();
HandleMark hm(calling_thread);
// growable array of jvmti monitors info on the C-heap
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list = new (mtServiceability) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, mtServiceability);
if (java_lang_VirtualThread::is_instance(thread_oop)) { // There is no monitor info to collect if target virtual thread is unmounted. if (java_thread != NULL) {
VirtualThreadGetOwnedMonitorInfoClosure op(this,
Handle(calling_thread, thread_oop),
owned_monitors_list);
Handshake::execute(&op, java_thread);
err = op.result();
}
} else {
EscapeBarrier eb(true, calling_thread, java_thread); if (!eb.deoptimize_objects(MaxJavaStackTraceDepth)) { delete owned_monitors_list; return JVMTI_ERROR_OUT_OF_MEMORY;
}
if (java_thread == calling_thread) { // It is only safe to make a direct call on the current thread. // All other usage needs to use a direct handshake for safety.
err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list);
} else { // get owned monitors info with handshake
GetOwnedMonitorInfoClosure op(calling_thread, this, owned_monitors_list);
Handshake::execute(&op, java_thread);
err = op.result();
}
}
jint owned_monitor_count = owned_monitors_list->length(); if (err == JVMTI_ERROR_NONE) { if ((err = allocate(owned_monitor_count * sizeof(jobject *),
(unsignedchar**)owned_monitors_ptr)) == JVMTI_ERROR_NONE) { // copy into the returned array for (int i = 0; i < owned_monitor_count; i++) {
(*owned_monitors_ptr)[i] =
((jvmtiMonitorStackDepthInfo*)owned_monitors_list->at(i))->monitor;
}
*owned_monitor_count_ptr = owned_monitor_count;
}
} // clean up. for (int i = 0; i < owned_monitor_count; i++) {
deallocate((unsignedchar*)owned_monitors_list->at(i));
} delete owned_monitors_list;
return err;
} /* end GetOwnedMonitorInfo */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // monitor_info_count_ptr - pre-checked for NULL // monitor_info_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) {
JavaThread* calling_thread = JavaThread::current();
HandleMark hm(calling_thread);
// growable array of jvmti monitors info on the C-heap
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list = new (mtServiceability) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, mtServiceability);
if (java_lang_VirtualThread::is_instance(thread_oop)) { // There is no monitor info to collect if target virtual thread is unmounted. if (java_thread != NULL) {
VirtualThreadGetOwnedMonitorInfoClosure op(this,
Handle(calling_thread, thread_oop),
owned_monitors_list);
Handshake::execute(&op, java_thread);
err = op.result();
}
} else {
EscapeBarrier eb(true, calling_thread, java_thread); if (!eb.deoptimize_objects(MaxJavaStackTraceDepth)) { delete owned_monitors_list; return JVMTI_ERROR_OUT_OF_MEMORY;
}
if (java_thread == calling_thread) { // It is only safe to make a direct call on the current thread. // All other usage needs to use a direct handshake for safety.
err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list);
} else { // get owned monitors info with handshake
GetOwnedMonitorInfoClosure op(calling_thread, this, owned_monitors_list);
Handshake::execute(&op, java_thread);
err = op.result();
}
}
jint owned_monitor_count = owned_monitors_list->length(); if (err == JVMTI_ERROR_NONE) { if ((err = allocate(owned_monitor_count * sizeof(jvmtiMonitorStackDepthInfo),
(unsignedchar**)monitor_info_ptr)) == JVMTI_ERROR_NONE) { // copy to output array. for (int i = 0; i < owned_monitor_count; i++) {
(*monitor_info_ptr)[i].monitor =
((jvmtiMonitorStackDepthInfo*)owned_monitors_list->at(i))->monitor;
(*monitor_info_ptr)[i].stack_depth =
((jvmtiMonitorStackDepthInfo*)owned_monitors_list->at(i))->stack_depth;
}
}
*monitor_info_count_ptr = owned_monitor_count;
}
// clean up. for (int i = 0; i < owned_monitor_count; i++) {
deallocate((unsignedchar*)owned_monitors_list->at(i));
} delete owned_monitors_list;
return err;
} /* end GetOwnedMonitorStackDepthInfo */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // monitor_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetCurrentContendedMonitor(jthread thread, jobject* monitor_ptr) {
JavaThread* calling_thread = JavaThread::current();
HandleMark hm(calling_thread);
if (java_lang_VirtualThread::is_instance(thread_oop)) { // There is no monitor info to collect if target virtual thread is unmounted. if (java_thread != NULL) {
GetCurrentContendedMonitorClosure op(calling_thread, this, monitor_ptr, /* is_virtual */ true);
Handshake::execute(&op, java_thread);
err = op.result();
} else {
*monitor_ptr = NULL; if (!JvmtiEnvBase::is_vthread_alive(thread_oop)) {
err = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
} return err;
} if (java_thread == calling_thread) { // It is only safe to make a direct call on the current thread. // All other usage needs to use a direct handshake for safety.
err = get_current_contended_monitor(calling_thread, java_thread, monitor_ptr, /* is_virtual */ false);
} else { // get contended monitor information with handshake
GetCurrentContendedMonitorClosure op(calling_thread, this, monitor_ptr, /* is_virtual */ false);
Handshake::execute(&op, java_thread);
err = op.result();
} return err;
} /* end GetCurrentContendedMonitor */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // proc - pre-checked for NULL // arg - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, constvoid* arg, jint priority) {
JavaThread* current_thread = JavaThread::current();
JavaThread* java_thread = NULL;
oop thread_oop = NULL;
ThreadsListHandle tlh(current_thread);
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop); if (err != JVMTI_ERROR_NONE) { // We got an error code so we don't have a JavaThread *, but // only return an error from here if we didn't get a valid // thread_oop. if (thread_oop == NULL) { return err;
} // We have a valid thread_oop.
}
if (java_thread != NULL) { // 'thread' refers to an existing JavaThread. return JVMTI_ERROR_INVALID_THREAD;
} if (java_lang_VirtualThread::is_instance(thread_oop)) { // No support for virtual threads. return JVMTI_ERROR_UNSUPPORTED_OPERATION;
}
JvmtiAgentThread* new_thread = new JvmtiAgentThread(this, proc, arg);
// At this point it may be possible that no osthread was created for the // JavaThread due to lack of resources. if (new_thread->osthread() == NULL) { // The new thread is not known to Thread-SMR yet so we can just delete. delete new_thread; return JVMTI_ERROR_OUT_OF_MEMORY;
}
// Only one top level thread group now.
*group_count_ptr = 1;
// Allocate memory to store global-refs to the thread groups. // Assume this area is freed by caller.
*groups_ptr = (jthreadGroup *) jvmtiMalloc((sizeof(jthreadGroup)) * (*group_count_ptr));
return JVMTI_ERROR_NONE;
} /* end GetThreadGroupChildren */
// // Stack Frame functions //
// thread - NOT protected by ThreadsListHandle and NOT pre-checked // max_frame_count - pre-checked to be greater than or equal to 0 // frame_buffer - pre-checked for NULL // count_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetStackTrace(jthread thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo* frame_buffer, jint* count_ptr) {
JavaThread* current_thread = JavaThread::current();
HandleMark hm(current_thread);
// It is only safe to perform the direct operation on the current // thread. All other usage needs to use a direct handshake for safety. if (java_thread == JavaThread::current()) {
err = get_stack_trace(java_thread, start_depth, max_frame_count, frame_buffer, count_ptr);
} else { // Get stack trace with handshake.
GetStackTraceClosure op(this, start_depth, max_frame_count, frame_buffer, count_ptr);
Handshake::execute(&op, java_thread);
err = op.result();
}
return err;
} /* end GetStackTrace */
// max_frame_count - pre-checked to be greater than or equal to 0 // stack_info_ptr - pre-checked for NULL // thread_count_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetAllStackTraces(jint max_frame_count, jvmtiStackInfo** stack_info_ptr, jint* thread_count_ptr) {
jvmtiError err = JVMTI_ERROR_NONE;
JavaThread* calling_thread = JavaThread::current();
// JVMTI get stack traces at safepoint.
VM_GetAllStackTraces op(this, calling_thread, max_frame_count);
VMThread::execute(&op);
*thread_count_ptr = op.final_thread_count();
*stack_info_ptr = op.stack_info();
err = op.result(); return err;
} /* end GetAllStackTraces */
// thread_count - pre-checked to be greater than or equal to 0 // thread_list - pre-checked for NULL // max_frame_count - pre-checked to be greater than or equal to 0 // stack_info_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list, jint max_frame_count, jvmtiStackInfo** stack_info_ptr) {
jvmtiError err = JVMTI_ERROR_NONE;
if (thread_count == 1) {
JvmtiVTMSTransitionDisabler disabler;
// Use direct handshake if we need to get only one stack trace.
JavaThread *current_thread = JavaThread::current();
ThreadsListHandle tlh(current_thread);
// It is only safe to perform the direct operation on the current // thread. All other usage needs to use a direct handshake for safety. if (java_thread == JavaThread::current()) {
err = get_frame_count(java_thread, count_ptr);
} else { // get java stack frame count with handshake.
GetFrameCountClosure op(this, count_ptr);
Handshake::execute(&op, java_thread);
err = op.result();
} return err;
} /* end GetFrameCount */
// thread - NOT protected by ThreadsListHandle and NOT pre-checked
jvmtiError
JvmtiEnv::PopFrame(jthread thread) {
JavaThread* current_thread = JavaThread::current();
HandleMark hm(current_thread);
if (thread == NULL) {
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.66 Sekunden
(vorverarbeitet)
¤
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 ist noch experimentell.