8248359: Update JVMCI

Reviewed-by: kvn, never
This commit is contained in:
Doug Simon 2020-07-01 12:06:44 +02:00
parent eb78035d05
commit 03d47d58d6
16 changed files with 799 additions and 505 deletions

View file

@ -1201,7 +1201,7 @@ void CompileBroker::compile_method_base(const methodHandle& method,
// Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown
// to avoid deadlock between compiler thread(s) and threads run at shutdown
// such as the DestroyJavaVM thread.
if (JVMCI::shutdown_called()) {
if (JVMCI::in_shutdown()) {
blocking = false;
}
}
@ -2150,16 +2150,22 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
TraceTime t1("compilation", &time);
EventCompilation event;
JVMCICompileState compile_state(task);
JVMCIRuntime *runtime = NULL;
if (JVMCI::in_shutdown()) {
failure_reason = "in JVMCI shutdown";
retry_message = "not retryable";
compilable = ciEnv::MethodCompilable_never;
} else if (compile_state.target_method_is_old()) {
// Skip redefined methods
if (compile_state.target_method_is_old()) {
failure_reason = "redefined method";
retry_message = "not retryable";
compilable = ciEnv::MethodCompilable_never;
} else {
JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__);
methodHandle method(thread, target_handle);
env.runtime()->compile_method(&env, jvmci, method, osr_bci);
runtime = env.runtime();
runtime->compile_method(&env, jvmci, method, osr_bci);
failure_reason = compile_state.failure_reason();
failure_reason_on_C_heap = compile_state.failure_reason_on_C_heap();

View file

@ -35,12 +35,12 @@
// to a GC in the shared library).
class JNIAccessMark : public StackObj {
private:
ThreadToNativeFromVM ttnfv;
HandleMark hm;
ThreadToNativeFromVM _ttnfv;
HandleMark _hm;
JNIEnv* _env;
public:
inline JNIAccessMark(JVMCIEnv* jvmci_env) :
ttnfv(JavaThread::current()), hm(JavaThread::current()) {
inline JNIAccessMark(JVMCIEnv* jvmci_env, JavaThread* thread=JavaThread::current()) :
_ttnfv(thread), _hm(thread) {
_env = jvmci_env->_env;
}
JNIEnv* env() const { return _env; }

View file

@ -24,17 +24,19 @@
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/oopStorage.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "jvmci/jvmci.hpp"
#include "jvmci/jvmciJavaClasses.hpp"
#include "jvmci/jvmciRuntime.hpp"
#include "jvmci/metadataHandleBlock.hpp"
#include "jvmci/metadataHandles.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
MetadataHandleBlock* JVMCI::_metadata_handles = NULL;
JVMCIRuntime* JVMCI::_compiler_runtime = NULL;
JVMCIRuntime* JVMCI::_java_runtime = NULL;
volatile bool JVMCI::_is_initialized = false;
void* JVMCI::_shared_library_handle = NULL;
char* JVMCI::_shared_library_path = NULL;
volatile bool JVMCI::_in_shutdown = false;
void jvmci_vmStructs_init() NOT_DEBUG_RETURN;
@ -50,6 +52,40 @@ bool JVMCI::can_initialize_JVMCI() {
return true;
}
void* JVMCI::get_shared_library(char*& path, bool load) {
void* sl_handle = _shared_library_handle;
if (sl_handle != NULL || !load) {
path = _shared_library_path;
return sl_handle;
}
assert(JVMCI_lock->owner() == Thread::current(), "must be");
path = NULL;
if (_shared_library_handle == NULL) {
char path[JVM_MAXPATHLEN];
char ebuf[1024];
if (JVMCILibPath != NULL) {
if (!os::dll_locate_lib(path, sizeof(path), JVMCILibPath, JVMCI_SHARED_LIBRARY_NAME)) {
vm_exit_during_initialization("Unable to locate JVMCI shared library in path specified by -XX:JVMCILibPath value", JVMCILibPath);
}
} else {
if (!os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), JVMCI_SHARED_LIBRARY_NAME)) {
vm_exit_during_initialization("Unable to create path to JVMCI shared library");
}
}
void* handle = os::dll_load(path, ebuf, sizeof ebuf);
if (handle == NULL) {
vm_exit_during_initialization("Unable to load JVMCI shared library", ebuf);
}
_shared_library_handle = handle;
_shared_library_path = strdup(path);
TRACE_jvmci_1("loaded JVMCI shared library from %s", path);
}
path = _shared_library_path;
return _shared_library_handle;
}
void JVMCI::initialize_compiler(TRAPS) {
if (JVMCILibDumpJNIConfig) {
JNIJVMCI::initialize_ids(NULL);
@ -61,93 +97,57 @@ void JVMCI::initialize_compiler(TRAPS) {
void JVMCI::initialize_globals() {
jvmci_vmStructs_init();
_metadata_handles = MetadataHandleBlock::allocate_block();
if (UseJVMCINativeLibrary) {
// There are two runtimes.
_compiler_runtime = new JVMCIRuntime();
_java_runtime = new JVMCIRuntime();
_compiler_runtime = new JVMCIRuntime(0);
_java_runtime = new JVMCIRuntime(-1);
} else {
// There is only a single runtime
_java_runtime = _compiler_runtime = new JVMCIRuntime();
_java_runtime = _compiler_runtime = new JVMCIRuntime(0);
}
}
// Handles to objects in the Hotspot heap.
static OopStorage* object_handles() {
return OopStorageSet::vm_global();
}
jobject JVMCI::make_global(const Handle& obj) {
assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
assert(oopDesc::is_oop(obj()), "not an oop");
oop* ptr = object_handles()->allocate();
jobject res = NULL;
if (ptr != NULL) {
assert(*ptr == NULL, "invariant");
NativeAccess<>::oop_store(ptr, obj());
res = reinterpret_cast<jobject>(ptr);
} else {
vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR,
"Cannot create JVMCI oop handle");
}
return res;
}
void JVMCI::destroy_global(jobject handle) {
// Assert before nulling out, for better debugging.
assert(is_global_handle(handle), "precondition");
oop* oop_ptr = reinterpret_cast<oop*>(handle);
NativeAccess<>::oop_store(oop_ptr, (oop)NULL);
object_handles()->release(oop_ptr);
}
bool JVMCI::is_global_handle(jobject handle) {
const oop* ptr = reinterpret_cast<oop*>(handle);
return object_handles()->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY;
}
jmetadata JVMCI::allocate_handle(const methodHandle& handle) {
assert(_metadata_handles != NULL, "uninitialized");
MutexLocker ml(JVMCI_lock);
return _metadata_handles->allocate_handle(handle);
}
jmetadata JVMCI::allocate_handle(const constantPoolHandle& handle) {
assert(_metadata_handles != NULL, "uninitialized");
MutexLocker ml(JVMCI_lock);
return _metadata_handles->allocate_handle(handle);
}
void JVMCI::release_handle(jmetadata handle) {
MutexLocker ml(JVMCI_lock);
_metadata_handles->chain_free_list(handle);
}
void JVMCI::metadata_do(void f(Metadata*)) {
if (_metadata_handles != NULL) {
_metadata_handles->metadata_do(f);
if (_java_runtime != NULL) {
_java_runtime->_metadata_handles->metadata_do(f);
}
if (_compiler_runtime != NULL && _compiler_runtime != _java_runtime) {
_compiler_runtime->_metadata_handles->metadata_do(f);
}
}
void JVMCI::do_unloading(bool unloading_occurred) {
if (_metadata_handles != NULL && unloading_occurred) {
_metadata_handles->do_unloading();
if (unloading_occurred) {
if (_java_runtime != NULL) {
_java_runtime->_metadata_handles->do_unloading();
}
if (_compiler_runtime != NULL && _compiler_runtime != _java_runtime) {
_compiler_runtime->_metadata_handles->do_unloading();
}
}
}
bool JVMCI::is_compiler_initialized() {
return compiler_runtime()->is_HotSpotJVMCIRuntime_initialized();
return _is_initialized;
}
void JVMCI::shutdown() {
ResourceMark rm;
{
MutexLocker locker(JVMCI_lock);
_in_shutdown = true;
TRACE_jvmci_1("shutting down JVMCI");
}
JVMCIRuntime* java_runtime = _java_runtime;
if (java_runtime != compiler_runtime()) {
java_runtime->shutdown();
}
if (compiler_runtime() != NULL) {
compiler_runtime()->shutdown();
}
}
bool JVMCI::shutdown_called() {
if (compiler_runtime() != NULL) {
return compiler_runtime()->shutdown_called();
}
return false;
bool JVMCI::in_shutdown() {
return _in_shutdown;
}

View file

@ -45,15 +45,24 @@ class JVMCI : public AllStatic {
friend class JVMCIEnv;
private:
// Handles to Metadata objects.
static MetadataHandleBlock* _metadata_handles;
// Access to the HotSpotJVMCIRuntime used by the CompileBroker.
static JVMCIRuntime* _compiler_runtime;
// Access to the HotSpotJVMCIRuntime used by Java code running on the
// HotSpot heap. It will be the same as _compiler_runtime if
// UseJVMCINativeLibrary is false
// True when at least one JVMCIRuntime::initialize_HotSpotJVMCIRuntime()
// execution has completed successfully.
static volatile bool _is_initialized;
// Handle created when loading the JVMCI shared library with os::dll_load.
// Must hold JVMCI_lock when initializing.
static void* _shared_library_handle;
// Argument to os::dll_load when loading JVMCI shared library
static char* _shared_library_path;
// Records whether JVMCI::shutdown has been called.
static volatile bool _in_shutdown;
// Access to the HotSpot heap based JVMCIRuntime
static JVMCIRuntime* _java_runtime;
public:
@ -64,13 +73,20 @@ class JVMCI : public AllStatic {
code_too_large
};
// Gets the handle to the loaded JVMCI shared library, loading it
// first if not yet loaded and `load` is true. The path from
// which the library is loaded is returned in `path`. If
// `load` is true then JVMCI_lock must be locked.
static void* get_shared_library(char*& path, bool load);
static void do_unloading(bool unloading_occurred);
static void metadata_do(void f(Metadata*));
static void shutdown();
static bool shutdown_called();
// Returns whether JVMCI::shutdown has been called.
static bool in_shutdown();
static bool is_compiler_initialized();
@ -83,16 +99,9 @@ class JVMCI : public AllStatic {
static void initialize_compiler(TRAPS);
static jobject make_global(const Handle& obj);
static void destroy_global(jobject handle);
static bool is_global_handle(jobject handle);
static jmetadata allocate_handle(const methodHandle& handle);
static jmetadata allocate_handle(const constantPoolHandle& handle);
static void release_handle(jmetadata handle);
static JVMCIRuntime* compiler_runtime() { return _compiler_runtime; }
// Gets the single runtime for JVMCI on the Java heap. This is the only
// JVMCI runtime available when !UseJVMCINativeLibrary.
static JVMCIRuntime* java_runtime() { return _java_runtime; }
};

View file

@ -99,29 +99,28 @@ void JVMCICompiler::bootstrap(TRAPS) {
(jlong)nanos_to_millis(os::javaTimeNanos() - start), _methods_compiled);
}
_bootstrapping = false;
JVMCI::compiler_runtime()->bootstrap_finished(CHECK);
JVMCI::java_runtime()->bootstrap_finished(CHECK);
}
bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) {
if (UseJVMCINativeLibrary) {
// This mechanism exists to force compilation of a JVMCI compiler by C1
// to reduces the compilation time spent on the JVMCI compiler itself. In
// +UseJVMCINativeLibrary mode, the JVMCI compiler is AOT compiled.
return false;
}
if (_bootstrapping) {
// When bootstrapping, the JVMCI compiler can compile its own methods.
return false;
}
JVMCIRuntime* runtime = JVMCI::compiler_runtime();
if (runtime != NULL && runtime->is_HotSpotJVMCIRuntime_initialized()) {
JavaThread* thread = JavaThread::current();
HandleMark hm(thread);
THREAD_JVMCIENV(thread);
JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(JVMCIENV);
objArrayHandle excludeModules(thread, HotSpotJVMCI::HotSpotJVMCIRuntime::excludeFromJVMCICompilation(JVMCIENV, HotSpotJVMCI::resolve(receiver)));
if (UseJVMCINativeLibrary) {
// This mechanism exists to force compilation of a JVMCI compiler by C1
// to reduce the compilation time spent on the JVMCI compiler itself. In
// +UseJVMCINativeLibrary mode, the JVMCI compiler is AOT compiled.
return false;
} else {
JVMCIRuntime* runtime = JVMCI::java_runtime();
if (runtime != NULL) {
JVMCIObject receiver = runtime->probe_HotSpotJVMCIRuntime();
if (receiver.is_null()) {
return false;
}
JVMCIEnv* ignored_env = NULL;
objArrayHandle excludeModules(JavaThread::current(), HotSpotJVMCI::HotSpotJVMCIRuntime::excludeFromJVMCICompilation(ignored_env, HotSpotJVMCI::resolve(receiver)));
if (excludeModules.not_null()) {
ModuleEntry* moduleEntry = method->method_holder()->module();
for (int i = 0; i < excludeModules->length(); i++) {
@ -133,6 +132,7 @@ bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) {
}
return false;
}
}
// Compilation entry point for methods
void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) {

View file

@ -103,14 +103,10 @@ class JVMCITraceMark : public StackObj {
public:
JVMCITraceMark(const char* msg) {
_msg = msg;
if (JVMCITraceLevel >= 1) {
tty->print_cr(PTR_FORMAT " JVMCITrace-1: Enter %s", p2i(JavaThread::current()), _msg);
}
TRACE_jvmci_2("Enter %s", _msg);
}
~JVMCITraceMark() {
if (JVMCITraceLevel >= 1) {
tty->print_cr(PTR_FORMAT " JVMCITrace-1: Exit %s", p2i(JavaThread::current()), _msg);
}
TRACE_jvmci_2(" Exit %s", _msg);
}
};
@ -137,35 +133,37 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) {
ResourceMark rm; \
JNI_JVMCIENV(thread, env);
static Thread* get_current_thread() {
return Thread::current_or_null_safe();
static JavaThread* get_current_thread(bool allow_null=true) {
Thread* thread = Thread::current_or_null_safe();
if (thread == NULL) {
assert(allow_null, "npe");
return NULL;
}
assert(thread->is_Java_thread(), "must be");
return (JavaThread*) thread;
}
// Entry to native method implementation that transitions
// current thread to '_thread_in_vm'.
#define C2V_VMENTRY(result_type, name, signature) \
JNIEXPORT result_type JNICALL c2v_ ## name signature { \
Thread* base_thread = get_current_thread(); \
if (base_thread == NULL) { \
JavaThread* thread = get_current_thread(); \
if (thread == NULL) { \
env->ThrowNew(JNIJVMCI::InternalError::clazz(), \
err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
return; \
} \
assert(base_thread->is_Java_thread(), "just checking");\
JavaThread* thread = (JavaThread*) base_thread; \
JVMCITraceMark jtm("CompilerToVM::" #name); \
C2V_BLOCK(result_type, name, signature)
#define C2V_VMENTRY_(result_type, name, signature, result) \
JNIEXPORT result_type JNICALL c2v_ ## name signature { \
Thread* base_thread = get_current_thread(); \
if (base_thread == NULL) { \
JavaThread* thread = get_current_thread(); \
if (thread == NULL) { \
env->ThrowNew(JNIJVMCI::InternalError::clazz(), \
err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
return result; \
} \
assert(base_thread->is_Java_thread(), "just checking");\
JavaThread* thread = (JavaThread*) base_thread; \
JVMCITraceMark jtm("CompilerToVM::" #name); \
C2V_BLOCK(result_type, name, signature)
@ -176,7 +174,7 @@ static Thread* get_current_thread() {
// current thread to '_thread_in_vm'.
#define C2V_VMENTRY_PREFIX(result_type, name, signature) \
JNIEXPORT result_type JNICALL c2v_ ## name signature { \
Thread* base_thread = get_current_thread();
JavaThread* thread = get_current_thread();
#define C2V_END }
@ -1579,7 +1577,7 @@ extern "C" void jio_printf(const char *fmt, ...);
class AttachDetach : public StackObj {
public:
bool _attached;
AttachDetach(JNIEnv* env, Thread* current_thread) {
AttachDetach(JNIEnv* env, JavaThread* current_thread) {
if (current_thread == NULL) {
extern struct JavaVM_ main_vm;
JNIEnv* hotspotEnv;
@ -1608,18 +1606,17 @@ class AttachDetach : public StackObj {
};
C2V_VMENTRY_PREFIX(jint, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length, bool flush, bool can_throw))
AttachDetach ad(env, base_thread);
AttachDetach ad(env, thread);
bool use_tty = true;
if (base_thread == NULL) {
if (thread == NULL) {
if (!ad._attached) {
// Can only use tty if the current thread is attached
TRACE_jvmci_1("Cannot write to tty on unattached thread");
return 0;
}
base_thread = get_current_thread();
thread = get_current_thread();
}
JVMCITraceMark jtm("writeDebugOutput");
assert(base_thread->is_Java_thread(), "just checking");
JavaThread* thread = (JavaThread*) base_thread;
C2V_BLOCK(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length))
if (bytes == NULL) {
if (can_throw) {
@ -2229,7 +2226,7 @@ C2V_VMENTRY_NULL(jobject, getObject, (JNIEnv* env, jobject, jobject x, long disp
C2V_VMENTRY(void, deleteGlobalHandle, (JNIEnv* env, jobject, jlong h))
jobject handle = (jobject)(address)h;
if (handle != NULL) {
JVMCI::destroy_global(handle);
JVMCIENV->runtime()->destroy_global(handle);
}
}
@ -2239,31 +2236,24 @@ static void requireJVMCINativeLibrary(JVMCI_TRAPS) {
}
}
static JavaVM* requireNativeLibraryJavaVM(const char* caller, JVMCI_TRAPS) {
JavaVM* javaVM = JVMCIEnv::get_shared_library_javavm();
if (javaVM == NULL) {
JVMCI_THROW_MSG_NULL(IllegalStateException, err_msg("Require JVMCI shared library to be initialized in %s", caller));
}
return javaVM;
}
C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclass mirror))
requireJVMCINativeLibrary(JVMCI_CHECK_NULL);
requireInHotSpot("registerNativeMethods", JVMCI_CHECK_NULL);
void* shared_library = JVMCIEnv::get_shared_library_handle();
if (shared_library == NULL) {
char* sl_path;
void* sl_handle;
JVMCIRuntime* runtime = JVMCI::compiler_runtime();
{
// Ensure the JVMCI shared library runtime is initialized.
JVMCIEnv __peer_jvmci_env__(thread, false, __FILE__, __LINE__);
JVMCIEnv* peerEnv = &__peer_jvmci_env__;
HandleMark hm;
JVMCIRuntime* runtime = JVMCI::compiler_runtime();
JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerEnv);
if (peerEnv->has_pending_exception()) {
peerEnv->describe_pending_exception(true);
}
shared_library = JVMCIEnv::get_shared_library_handle();
if (shared_library == NULL) {
JVMCI_THROW_MSG_0(InternalError, "Error initializing JVMCI runtime");
sl_handle = JVMCI::get_shared_library(sl_path, false);
if (sl_handle == NULL) {
JVMCI_THROW_MSG_0(InternalError, err_msg("Error initializing JVMCI runtime %d", runtime->id()));
}
}
@ -2293,7 +2283,7 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas
os::print_jni_name_suffix_on(&st, args_size);
char* jni_name = st.as_string();
address entry = (address) os::dll_lookup(shared_library, jni_name);
address entry = (address) os::dll_lookup(sl_handle, jni_name);
if (entry == NULL) {
// 2) Try JNI long style
st.reset();
@ -2303,11 +2293,11 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas
st.print_raw(long_name);
os::print_jni_name_suffix_on(&st, args_size);
char* jni_long_name = st.as_string();
entry = (address) os::dll_lookup(shared_library, jni_long_name);
entry = (address) os::dll_lookup(sl_handle, jni_long_name);
if (entry == NULL) {
JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]",
method->name_and_sig_as_C_string(),
jni_name, jni_long_name, JVMCIEnv::get_shared_library_path()));
jni_name, jni_long_name, sl_path));
}
}
@ -2316,51 +2306,49 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas
method->name_and_sig_as_C_string(), p2i(method->native_function()), p2i(entry)));
}
method->set_native_function(entry, Method::native_bind_event_is_interesting);
log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI]",
log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI] @ " PTR_FORMAT,
method->method_holder()->external_name(),
method->name()->as_C_string());
method->name()->as_C_string(),
p2i((void*) entry));
}
}
JavaVM* javaVM = JVMCIEnv::get_shared_library_javavm();
JVMCIPrimitiveArray result = JVMCIENV->new_longArray(4, JVMCI_CHECK_NULL);
JVMCIENV->put_long_at(result, 0, (jlong) (address) javaVM);
JVMCIENV->put_long_at(result, 1, (jlong) (address) javaVM->functions->reserved0);
JVMCIENV->put_long_at(result, 2, (jlong) (address) javaVM->functions->reserved1);
JVMCIENV->put_long_at(result, 3, (jlong) (address) javaVM->functions->reserved2);
return (jlongArray) JVMCIENV->get_jobject(result);
typeArrayOop info_oop = oopFactory::new_longArray(4, CHECK_0);
jlongArray info = (jlongArray) JNIHandles::make_local(info_oop);
runtime->init_JavaVM_info(info, JVMCI_CHECK_0);
return info;
}
C2V_VMENTRY_PREFIX(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject c2vm))
if (base_thread == NULL) {
if (thread == NULL) {
// Called from unattached JVMCI shared library thread
return false;
}
JVMCITraceMark jtm("isCurrentThreadAttached");
assert(base_thread->is_Java_thread(), "just checking");
JavaThread* thread = (JavaThread*) base_thread;
if (thread->jni_environment() == env) {
C2V_BLOCK(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject))
requireJVMCINativeLibrary(JVMCI_CHECK_0);
JavaVM* javaVM = requireNativeLibraryJavaVM("isCurrentThreadAttached", JVMCI_CHECK_0);
JVMCIRuntime* runtime = JVMCI::compiler_runtime();
if (runtime == NULL || !runtime->has_shared_library_javavm()) {
JVMCI_THROW_MSG_0(IllegalStateException, "Require JVMCI shared library JavaVM to be initialized in isCurrentThreadAttached");
}
JNIEnv* peerEnv;
return javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) == JNI_OK;
return runtime->GetEnv(thread, (void**) &peerEnv, JNI_VERSION_1_2) == JNI_OK;
}
return true;
C2V_END
C2V_VMENTRY_PREFIX(jlong, getCurrentJavaThread, (JNIEnv* env, jobject c2vm))
if (base_thread == NULL) {
if (thread == NULL) {
// Called from unattached JVMCI shared library thread
return 0L;
}
JVMCITraceMark jtm("getCurrentJavaThread");
assert(base_thread->is_Java_thread(), "just checking");
return (jlong) p2i(base_thread);
return (jlong) p2i(thread);
C2V_END
C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jboolean as_daemon))
if (base_thread == NULL) {
if (thread == NULL) {
// Called from unattached JVMCI shared library thread
extern struct JavaVM_ main_vm;
JNIEnv* hotspotEnv;
@ -2372,25 +2360,29 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb
return true;
}
JVMCITraceMark jtm("attachCurrentThread");
assert(base_thread->is_Java_thread(), "just checking");\
JavaThread* thread = (JavaThread*) base_thread;
if (thread->jni_environment() == env) {
// Called from HotSpot
C2V_BLOCK(jboolean, attachCurrentThread, (JNIEnv* env, jobject, jboolean))
requireJVMCINativeLibrary(JVMCI_CHECK_0);
JavaVM* javaVM = requireNativeLibraryJavaVM("attachCurrentThread", JVMCI_CHECK_0);
JVMCIRuntime* runtime = JVMCI::compiler_runtime();
if (runtime == NULL || !runtime->has_shared_library_javavm()) {
JVMCI_THROW_MSG_0(IllegalStateException, "Require JVMCI shared library JavaVM to be initialized in attachCurrentThread");
}
JavaVMAttachArgs attach_args;
attach_args.version = JNI_VERSION_1_2;
attach_args.name = thread->name();
attach_args.group = NULL;
JNIEnv* peerEnv;
if (javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) == JNI_OK) {
JNIEnv* peerJNIEnv;
if (runtime->GetEnv(thread, (void**) &peerJNIEnv, JNI_VERSION_1_2) == JNI_OK) {
return false;
}
jint res = as_daemon ? javaVM->AttachCurrentThreadAsDaemon((void**)&peerEnv, &attach_args) :
javaVM->AttachCurrentThread((void**)&peerEnv, &attach_args);
jint res = as_daemon ? runtime->AttachCurrentThreadAsDaemon(thread, (void**) &peerJNIEnv, &attach_args) :
runtime->AttachCurrentThread(thread, (void**) &peerJNIEnv, &attach_args);
if (res == JNI_OK) {
guarantee(peerEnv != NULL, "must be");
guarantee(peerJNIEnv != NULL, "must be");
TRACE_jvmci_1("attached to JavaVM for JVMCI runtime %d", runtime->id());
return true;
}
JVMCI_THROW_MSG_0(InternalError, err_msg("Error %d while attaching %s", res, attach_args.name));
@ -2400,24 +2392,25 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb
C2V_END
C2V_VMENTRY_PREFIX(void, detachCurrentThread, (JNIEnv* env, jobject c2vm))
if (base_thread == NULL) {
if (thread == NULL) {
// Called from unattached JVMCI shared library thread
JNI_THROW("detachCurrentThread", IllegalStateException, err_msg("Cannot detach non-attached thread"));
JNI_THROW("detachCurrentThread", IllegalStateException, "Cannot detach non-attached thread");
}
JVMCITraceMark jtm("detachCurrentThread");
assert(base_thread->is_Java_thread(), "just checking");\
JavaThread* thread = (JavaThread*) base_thread;
if (thread->jni_environment() == env) {
// Called from HotSpot
C2V_BLOCK(void, detachCurrentThread, (JNIEnv* env, jobject))
requireJVMCINativeLibrary(JVMCI_CHECK);
requireInHotSpot("detachCurrentThread", JVMCI_CHECK);
JavaVM* javaVM = requireNativeLibraryJavaVM("detachCurrentThread", JVMCI_CHECK);
JNIEnv* peerEnv;
if (javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) != JNI_OK) {
JVMCIRuntime* runtime = JVMCI::compiler_runtime();
if (runtime == NULL || !runtime->has_shared_library_javavm()) {
JVMCI_THROW_MSG(IllegalStateException, "Require JVMCI shared library JavaVM to be initialized in detachCurrentThread");
}
JNIEnv* peerJNIEnv;
if (runtime->GetEnv(thread, (void**) &peerJNIEnv, JNI_VERSION_1_2) != JNI_OK) {
JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot detach non-attached thread: %s", thread->name()));
}
jint res = javaVM->DetachCurrentThread();
jint res = runtime->DetachCurrentThread(thread);
if (res != JNI_OK) {
JVMCI_THROW_MSG(InternalError, err_msg("Error %d while attaching %s", res, thread->name()));
}
@ -2426,7 +2419,7 @@ C2V_VMENTRY_PREFIX(void, detachCurrentThread, (JNIEnv* env, jobject c2vm))
extern struct JavaVM_ main_vm;
jint res = main_vm.DetachCurrentThread();
if (res != JNI_OK) {
JNI_THROW("detachCurrentThread", InternalError, err_msg("Cannot detach non-attached thread"));
JNI_THROW("detachCurrentThread", InternalError, "Cannot detach non-attached thread");
}
}
C2V_END

View file

@ -77,10 +77,6 @@ bool JVMCICompileState::jvmti_state_changed() const {
return false;
}
JavaVM* JVMCIEnv::_shared_library_javavm = NULL;
void* JVMCIEnv::_shared_library_handle = NULL;
char* JVMCIEnv::_shared_library_path = NULL;
void JVMCIEnv::copy_saved_properties() {
assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image");
@ -131,7 +127,7 @@ void JVMCIEnv::copy_saved_properties() {
// Initialize saved properties in shared library
jclass servicesClass = JNIJVMCI::Services::clazz();
jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method();
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject());
if (jni()->ExceptionCheck()) {
jni()->ExceptionDescribe();
@ -139,67 +135,14 @@ void JVMCIEnv::copy_saved_properties() {
}
}
JNIEnv* JVMCIEnv::init_shared_library(JavaThread* thread) {
if (_shared_library_javavm == NULL) {
MutexLocker locker(JVMCI_lock);
if (_shared_library_javavm == NULL) {
char path[JVM_MAXPATHLEN];
char ebuf[1024];
if (JVMCILibPath != NULL) {
if (!os::dll_locate_lib(path, sizeof(path), JVMCILibPath, JVMCI_SHARED_LIBRARY_NAME)) {
vm_exit_during_initialization("Unable to create JVMCI shared library path from -XX:JVMCILibPath value", JVMCILibPath);
}
} else {
if (!os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), JVMCI_SHARED_LIBRARY_NAME)) {
vm_exit_during_initialization("Unable to create path to JVMCI shared library");
}
}
void* handle = os::dll_load(path, ebuf, sizeof ebuf);
if (handle == NULL) {
vm_exit_during_initialization("Unable to load JVMCI shared library", ebuf);
}
_shared_library_handle = handle;
_shared_library_path = strdup(path);
jint (*JNI_CreateJavaVM)(JavaVM **pvm, void **penv, void *args);
typedef jint (*JNI_CreateJavaVM_t)(JavaVM **pvm, void **penv, void *args);
JNI_CreateJavaVM = CAST_TO_FN_PTR(JNI_CreateJavaVM_t, os::dll_lookup(handle, "JNI_CreateJavaVM"));
JNIEnv* env;
if (JNI_CreateJavaVM == NULL) {
vm_exit_during_initialization("Unable to find JNI_CreateJavaVM", path);
}
ResourceMark rm;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.ignoreUnrecognized = JNI_TRUE;
vm_args.options = NULL;
vm_args.nOptions = 0;
JavaVM* the_javavm = NULL;
int result = (*JNI_CreateJavaVM)(&the_javavm, (void**) &env, &vm_args);
if (result == JNI_OK) {
guarantee(env != NULL, "missing env");
_shared_library_javavm = the_javavm;
return env;
} else {
vm_exit_during_initialization(err_msg("JNI_CreateJavaVM failed with return value %d", result), path);
}
}
}
return NULL;
}
void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
assert(thread != NULL, "npe");
// By default there is only one runtime which is the compiler runtime.
_runtime = JVMCI::compiler_runtime();
_env = NULL;
_pop_frame_on_close = false;
_detach_on_close = false;
if (!UseJVMCINativeLibrary) {
// In HotSpot mode, JNI isn't used at all.
_runtime = JVMCI::java_runtime();
_is_hotspot = true;
return;
}
@ -213,6 +156,8 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
_runtime = JVMCI::java_runtime();
return;
}
_runtime = JVMCI::compiler_runtime();
assert(_runtime != NULL, "npe");
_env = parent_env;
return;
}
@ -220,13 +165,15 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
// Running in JVMCI shared library mode so ensure the shared library
// is loaded and initialized and get a shared library JNIEnv
_is_hotspot = false;
_env = init_shared_library(thread);
_runtime = JVMCI::compiler_runtime();
_env = _runtime->init_shared_library_javavm();
if (_env != NULL) {
// Creating the JVMCI shared library VM also attaches the current thread
_detach_on_close = true;
} else {
_shared_library_javavm->GetEnv((void**)&parent_env, JNI_VERSION_1_2);
_runtime->GetEnv(thread, (void**)&parent_env, JNI_VERSION_1_2);
if (parent_env != NULL) {
// Even though there's a parent JNI env, there's no guarantee
// it was opened by a JVMCIEnv scope and thus may not have
@ -240,7 +187,7 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
attach_args.version = JNI_VERSION_1_2;
attach_args.name = thread->name();
attach_args.group = NULL;
if (_shared_library_javavm->AttachCurrentThread((void**)&_env, &attach_args) != JNI_OK) {
if (_runtime->AttachCurrentThread(thread, (void**) &_env, &attach_args) != JNI_OK) {
fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name);
}
_detach_on_close = true;
@ -250,7 +197,7 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
assert(_env != NULL, "missing env");
assert(_throw_to_caller == false, "must be");
JNIAccessMark jni(this);
JNIAccessMark jni(this, thread);
jint result = _env->PushLocalFrame(32);
if (result != JNI_OK) {
char message[256];
@ -294,6 +241,7 @@ void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int l
// Prints a pending exception (if any) and its stack trace.
void JVMCIEnv::describe_pending_exception(bool clear) {
Thread* THREAD = Thread::current();
if (!is_hotspot()) {
JNIAccessMark jni(this);
if (jni()->ExceptionCheck()) {
@ -304,7 +252,6 @@ void JVMCIEnv::describe_pending_exception(bool clear) {
}
}
} else {
Thread* THREAD = Thread::current();
if (HAS_PENDING_EXCEPTION) {
JVMCIRuntime::describe_pending_hotspot_exception((JavaThread*) THREAD, clear);
}
@ -332,7 +279,7 @@ void JVMCIEnv::translate_hotspot_exception_to_jni_exception(JavaThread* THREAD,
ResourceMark rm;
const char* encoded_throwable_chars = java_lang_String::as_utf8_string(encoded_throwable_string);
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject jni_encoded_throwable_string = jni()->NewStringUTF(encoded_throwable_chars);
jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(),
@ -368,7 +315,7 @@ JVMCIEnv::~JVMCIEnv() {
}
if (_detach_on_close) {
get_shared_library_javavm()->DetachCurrentThread();
_runtime->DetachCurrentThread(JavaThread::current());
}
}
}
@ -603,12 +550,12 @@ JVMCIObject JVMCIEnv::create_box(BasicType type, jvalue* value, JVMCI_TRAPS) {
default:
JVMCI_THROW_MSG_(IllegalArgumentException, "Only boxes for primitive values can be created", JVMCIObject());
}
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
oop box = java_lang_boxing_object::create(type, value, CHECK_(JVMCIObject()));
return HotSpotJVMCI::wrap(box);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject box = jni()->NewObjectA(JNIJVMCI::box_class(type), JNIJVMCI::box_constructor(type), value);
assert(box != NULL, "");
return wrap(box);
@ -672,13 +619,13 @@ void JVMCIEnv::fthrow_error(const char* file, int line, const char* format, ...)
vsnprintf(msg, max_msg_size, format, ap);
msg[max_msg_size-1] = '\0';
va_end(ap);
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
Handle h_loader = Handle();
Handle h_protection_domain = Handle();
Exceptions::_throw_msg(THREAD, file, line, vmSymbols::jdk_vm_ci_common_JVMCIError(), msg, h_loader, h_protection_domain);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jni()->ThrowNew(JNIJVMCI::JVMCIError::clazz(), msg);
}
}
@ -735,7 +682,7 @@ void JVMCIEnv::call_HotSpotJVMCIRuntime_shutdown (JVMCIObject runtime) {
JavaValue result(T_VOID);
JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::shutdown_name(), vmSymbols::void_method_signature(), &jargs, THREAD);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::shutdown_method());
}
if (has_pending_exception()) {
@ -753,7 +700,7 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_runtime (JVMCIEnv* JVMCIENV) {
JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::runtime_name(), vmSymbols::runtime_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::runtime_method());
if (jni()->ExceptionCheck()) {
return JVMCIObject();
@ -770,7 +717,7 @@ JVMCIObject JVMCIEnv::call_JVMCI_getRuntime (JVMCIEnv* JVMCIENV) {
JavaCalls::call_static(&result, HotSpotJVMCI::JVMCI::klass(), vmSymbols::getRuntime_name(), vmSymbols::getRuntime_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::JVMCI::clazz(), JNIJVMCI::JVMCI::getRuntime_method());
if (jni()->ExceptionCheck()) {
return JVMCIObject();
@ -788,7 +735,7 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_getCompiler (JVMCIObject runtime,
JavaCalls::call_virtual(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::getCompiler_name(), vmSymbols::getCompiler_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->CallObjectMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::getCompiler_method());
if (jni()->ExceptionCheck()) {
return JVMCIObject();
@ -810,7 +757,7 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(JVMCIObject object,
vmSymbols::callToString_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::callToString_method(),
object.as_jobject());
@ -835,7 +782,7 @@ JVMCIObject JVMCIEnv::call_PrimitiveConstant_forTypeChar(jchar kind, jlong value
vmSymbols::forTypeChar_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::PrimitiveConstant::clazz(),
JNIJVMCI::PrimitiveConstant::forTypeChar_method(),
kind, value);
@ -858,7 +805,7 @@ JVMCIObject JVMCIEnv::call_JavaConstant_forFloat(float value, JVMCI_TRAPS) {
vmSymbols::forFloat_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(),
JNIJVMCI::JavaConstant::forFloat_method(),
value);
@ -881,7 +828,7 @@ JVMCIObject JVMCIEnv::call_JavaConstant_forDouble(double value, JVMCI_TRAPS) {
vmSymbols::forDouble_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(),
JNIJVMCI::JavaConstant::forDouble_method(),
value);
@ -926,7 +873,7 @@ JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci,
HotSpotJVMCI::StackTraceElement::set_lineNumber(this, obj(), line_number);
return wrap(obj());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject declaring_class = jni()->NewStringUTF(declaring_class_str);
if (jni()->ExceptionCheck()) {
return JVMCIObject();
@ -978,7 +925,7 @@ JVMCIObject JVMCIEnv::new_HotSpotNmethod(const methodHandle& method, const char*
&jargs, CHECK_(JVMCIObject()));
return wrap(obj_h());
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject nameStr = name == NULL ? NULL : jni()->NewStringUTF(name);
if (jni()->ExceptionCheck()) {
return JVMCIObject();
@ -1015,18 +962,6 @@ JVMCIObject JVMCIEnv::make_global(JVMCIObject object) {
}
}
JVMCIObject JVMCIEnv::make_weak(JVMCIObject object) {
if (object.is_null()) {
return JVMCIObject();
}
if (is_hotspot()) {
return wrap(JNIHandles::make_weak_global(Handle(Thread::current(), HotSpotJVMCI::resolve(object))));
} else {
JNIAccessMark jni(this);
return wrap(jni()->NewWeakGlobalRef(object.as_jobject()));
}
}
void JVMCIEnv::destroy_local(JVMCIObject object) {
if (is_hotspot()) {
JNIHandles::destroy_local(object.as_jobject());
@ -1045,15 +980,6 @@ void JVMCIEnv::destroy_global(JVMCIObject object) {
}
}
void JVMCIEnv::destroy_weak(JVMCIObject object) {
if (is_hotspot()) {
JNIHandles::destroy_weak_global(object.as_jweak());
} else {
JNIAccessMark jni(this);
jni()->DeleteWeakGlobalRef(object.as_jweak());
}
}
const char* JVMCIEnv::klass_name(JVMCIObject object) {
if (is_hotspot()) {
return HotSpotJVMCI::resolve(object)->klass()->signature_name();
@ -1076,7 +1002,7 @@ JVMCIObject JVMCIEnv::get_jvmci_method(const methodHandle& method, JVMCI_TRAPS)
}
Thread* THREAD = Thread::current();
jmetadata handle = JVMCI::allocate_handle(method);
jmetadata handle = _runtime->allocate_handle(method);
jboolean exception = false;
if (is_hotspot()) {
JavaValue result(T_OBJECT);
@ -1099,13 +1025,13 @@ JVMCIObject JVMCIEnv::get_jvmci_method(const methodHandle& method, JVMCI_TRAPS)
}
if (exception) {
JVMCI::release_handle(handle);
_runtime->release_handle(handle);
return JVMCIObject();
}
assert(asMethod(method_object) == method(), "must be");
if (get_HotSpotResolvedJavaMethodImpl_metadataHandle(method_object) != (jlong) handle) {
JVMCI::release_handle(handle);
_runtime->release_handle(handle);
}
assert(!method_object.is_null(), "must be");
return method_object;
@ -1137,7 +1063,7 @@ JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS)
type = wrap((oop)result.get_jobject());
}
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
HandleMark hm(THREAD);
type = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedObjectTypeImpl::clazz(),
@ -1155,10 +1081,10 @@ JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS)
JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMCI_TRAPS) {
JVMCIObject cp_object;
jmetadata handle = JVMCI::allocate_handle(cp);
jmetadata handle = _runtime->allocate_handle(cp);
jboolean exception = false;
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
JavaValue result(T_OBJECT);
JavaCallArguments args;
args.push_long((jlong) handle);
@ -1172,7 +1098,7 @@ JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMC
cp_object = wrap((oop)result.get_jobject());
}
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
cp_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotConstantPool::clazz(),
JNIJVMCI::HotSpotConstantPool_fromMetaspace_method(),
(jlong) handle));
@ -1180,7 +1106,7 @@ JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMC
}
if (exception) {
JVMCI::release_handle(handle);
_runtime->release_handle(handle);
return JVMCIObject();
}
@ -1191,69 +1117,69 @@ JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMC
}
JVMCIPrimitiveArray JVMCIEnv::new_booleanArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_boolArray(length, CHECK_(JVMCIObject()));
return wrap(result);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jbooleanArray result = jni()->NewBooleanArray(length);
return wrap(result);
}
}
JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_byteArray(length, CHECK_(JVMCIObject()));
return wrap(result);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jbyteArray result = jni()->NewByteArray(length);
return wrap(result);
}
}
JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj ())->array_klass(CHECK_(JVMCIObject()));
objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject()));
return wrap(result);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::byte_array(), NULL);
return wrap(result);
}
}
JVMCIPrimitiveArray JVMCIEnv::new_intArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_intArray(length, CHECK_(JVMCIObject()));
return wrap(result);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jintArray result = jni()->NewIntArray(length);
return wrap(result);
}
}
JVMCIPrimitiveArray JVMCIEnv::new_longArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_longArray(length, CHECK_(JVMCIObject()));
return wrap(result);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jlongArray result = jni()->NewLongArray(length);
return wrap(result);
}
}
JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
HotSpotJVMCI::VMField::klass()->initialize(CHECK_(JVMCIObject()));
oop obj = HotSpotJVMCI::VMField::klass()->allocate_instance(CHECK_(JVMCIObject()));
HotSpotJVMCI::VMField::set_name(this, obj, HotSpotJVMCI::resolve(name));
@ -1263,7 +1189,7 @@ JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offs
HotSpotJVMCI::VMField::set_value(this, obj, HotSpotJVMCI::resolve(value));
return wrap(obj);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::VMField::clazz(),
JNIJVMCI::VMField::constructor(),
get_jobject(name), get_jobject(type), offset, address, get_jobject(value));
@ -1272,8 +1198,8 @@ JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offs
}
JVMCIObject JVMCIEnv::new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject value, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
HotSpotJVMCI::VMFlag::klass()->initialize(CHECK_(JVMCIObject()));
oop obj = HotSpotJVMCI::VMFlag::klass()->allocate_instance(CHECK_(JVMCIObject()));
HotSpotJVMCI::VMFlag::set_name(this, obj, HotSpotJVMCI::resolve(name));
@ -1281,7 +1207,7 @@ JVMCIObject JVMCIEnv::new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject
HotSpotJVMCI::VMFlag::set_value(this, obj, HotSpotJVMCI::resolve(value));
return wrap(obj);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::VMFlag::clazz(),
JNIJVMCI::VMFlag::constructor(),
get_jobject(name), get_jobject(type), get_jobject(value));
@ -1290,8 +1216,8 @@ JVMCIObject JVMCIEnv::new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject
}
JVMCIObject JVMCIEnv::new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
HotSpotJVMCI::VMIntrinsicMethod::klass()->initialize(CHECK_(JVMCIObject()));
oop obj = HotSpotJVMCI::VMIntrinsicMethod::klass()->allocate_instance(CHECK_(JVMCIObject()));
HotSpotJVMCI::VMIntrinsicMethod::set_declaringClass(this, obj, HotSpotJVMCI::resolve(declaringClass));
@ -1300,7 +1226,7 @@ JVMCIObject JVMCIEnv::new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObj
HotSpotJVMCI::VMIntrinsicMethod::set_id(this, obj, id);
return wrap(obj);
} else {
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::VMIntrinsicMethod::clazz(),
JNIJVMCI::VMIntrinsicMethod::constructor(),
get_jobject(declaringClass), get_jobject(name), get_jobject(descriptor), id);
@ -1346,7 +1272,7 @@ JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont
return wrap(constant);
} else {
jlong handle = make_handle(obj);
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::IndirectHotSpotObjectConstantImpl::clazz(),
JNIJVMCI::IndirectHotSpotObjectConstantImpl::constructor(),
handle, compressed, dont_register);
@ -1385,7 +1311,7 @@ JVMCIObject JVMCIEnv::wrap(jobject object) {
jlong JVMCIEnv::make_handle(const Handle& obj) {
assert(!obj.is_null(), "should only create handle for non-NULL oops");
jobject handle = JVMCI::make_global(obj);
jobject handle = _runtime->make_global(obj);
return (jlong) handle;
}
@ -1399,15 +1325,15 @@ oop JVMCIEnv::resolve_handle(jlong objectHandle) {
}
JVMCIObject JVMCIEnv::create_string(const char* str, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
Handle result = java_lang_String::create_from_str(str, CHECK_(JVMCIObject()));
return HotSpotJVMCI::wrap(result());
} else {
jobject result;
jboolean exception = false;
{
JNIAccessMark jni(this);
JNIAccessMark jni(this, THREAD);
result = jni()->NewStringUTF(str);
exception = jni()->ExceptionCheck();
}

View file

@ -44,8 +44,11 @@ class JVMCIRuntime;
#define JVMCI_EXCEPTION_CHECK(env, ...) \
do { \
if (env->ExceptionCheck()) { \
if (env != JavaThread::current()->jni_environment() && JVMCIEnv::get_shared_library_path() != NULL) { \
tty->print_cr("In JVMCI shared library (%s):", JVMCIEnv::get_shared_library_path()); \
if (env != JavaThread::current()->jni_environment()) { \
char* sl_path; \
if (::JVMCI::get_shared_library(sl_path, false) != NULL) { \
tty->print_cr("In JVMCI shared library (%s):", sl_path); \
} \
} \
tty->print_cr(__VA_ARGS__); \
return; \
@ -143,16 +146,6 @@ class JVMCICompileState : public ResourceObj {
class JVMCIEnv : public ResourceObj {
friend class JNIAccessMark;
static char* _shared_library_path; // argument to os:dll_load
static void* _shared_library_handle; // result of os::dll_load
static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library
// Initializes the shared library JavaVM if not already initialized.
// Returns the JNI interface pointer for the current thread
// if initialization was performed by this call, NULL if
// initialization was performed by a previous call.
static JNIEnv* init_shared_library(JavaThread* thread);
// Initializes the _env, _mode and _runtime fields.
void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env);
@ -384,10 +377,8 @@ public:
// These are analagous to the JNI routines
JVMCIObject make_local(JVMCIObject object);
JVMCIObject make_global(JVMCIObject object);
JVMCIObject make_weak(JVMCIObject object);
void destroy_local(JVMCIObject object);
void destroy_global(JVMCIObject object);
void destroy_weak(JVMCIObject object);
// Deoptimizes the nmethod (if any) in the HotSpotNmethod.address
// field of mirror. The field is subsequently zeroed.
@ -399,9 +390,6 @@ public:
JVMCICompileState* _compile_state;
public:
static JavaVM* get_shared_library_javavm() { return _shared_library_javavm; }
static void* get_shared_library_handle() { return _shared_library_handle; }
static char* get_shared_library_path() { return _shared_library_path; }
// Determines if this is for the JVMCI runtime in the HotSpot
// heap (true) or the shared library heap (false).

View file

@ -83,6 +83,7 @@ void HotSpotJVMCI::compute_offset(int &dest_offset, Klass* klass, const char* na
// accessor itself does not include a class initialization check.
ik->initialize(CHECK);
}
TRACE_jvmci_2(" field offset for %s %s.%s = %d", signature, ik->external_name(), name, dest_offset);
}
#ifndef PRODUCT
@ -118,6 +119,7 @@ jmethodID JNIJVMCI::_HotSpotResolvedPrimitiveType_fromMetaspace_method;
#define START_CLASS(className, fullClassName) { \
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::fullClassName(), true, CHECK); \
className::_klass = InstanceKlass::cast(k); \
TRACE_jvmci_2(" klass for %s = " PTR_FORMAT, k->external_name(), p2i(k)); \
className::_klass->initialize(CHECK);
#define END_CLASS }
@ -286,6 +288,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
if (env->ExceptionCheck()) {
return;
}
jfieldID current = fieldid;
if (static_field) {
// Class initialization barrier
fieldid = env->GetStaticFieldID(clazz, name, signature);
@ -293,6 +296,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
// Class initialization barrier
fieldid = env->GetFieldID(clazz, name, signature);
}
TRACE_jvmci_2(" jfieldID for %s %s.%s = " PTR_FORMAT, signature, class_name, name, p2i(fieldid));
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
@ -312,7 +316,9 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
jclass k = env->FindClass(current_class_name); \
JVMCI_EXCEPTION_CHECK(env, "FindClass(%s)", current_class_name); \
assert(k != NULL, #fullClassName " not initialized"); \
className::_class = (jclass) env->NewGlobalRef(k); \
k = (jclass) env->NewGlobalRef(k); \
TRACE_jvmci_2(" jclass for %s = " PTR_FORMAT, current_class_name, p2i(k)); \
className::_class = k; \
}
#define END_CLASS current_class_name = NULL; }
@ -333,9 +339,13 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
fileStream* st = JVMCIGlobals::get_jni_config_file(); \
st->print_cr("method %s %s %s", current_class_name, methodName, signature); \
} else { \
jmethodID current = dst; \
dst = env->jniGetMethod(clazz, methodName, signature); \
JVMCI_EXCEPTION_CHECK(env, #jniGetMethod "(%s.%s%s)", current_class_name, methodName, signature); \
JVMCI_EXCEPTION_CHECK(env, #jniGetMethod "(%s.%s%s)", \
current_class_name, methodName, signature); \
assert(dst != NULL, "uninitialized"); \
TRACE_jvmci_2(" jmethodID for %s.%s%s = " PTR_FORMAT, \
current_class_name, methodName, signature, p2i(dst)); \
}
#define GET_JNI_CONSTRUCTOR(clazz, signature) \
@ -493,30 +503,30 @@ void JNIJVMCI::initialize_ids(JNIEnv* env) {
#define CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(f))
}
static void register_natives_for_class(JNIEnv* env, jclass clazz, const char* name, const JNINativeMethod *methods, jint nMethods) {
if (clazz == NULL) {
clazz = env->FindClass(name);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
fatal("Could not find class %s", name);
}
}
env->RegisterNatives(clazz, methods, nMethods);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
fatal("Failure registering natives for %s", name);
}
}
void JNIJVMCI::register_natives(JNIEnv* env) {
if (env != JavaThread::current()->jni_environment()) {
jclass clazz = env->FindClass("jdk/vm/ci/hotspot/CompilerToVM");
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
guarantee(false, "Could not find class jdk/vm/ci/hotspot/CompilerToVM");
}
JNINativeMethod CompilerToVM_native_methods[] = {
{ CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) },
};
env->RegisterNatives(clazz, CompilerToVM_native_methods, 1);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
guarantee(false, "");
}
JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) }};
JNINativeMethod JVMCI_nmethods[] = {{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }};
JNINativeMethod JVMCI_native_methods[] = {
{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) },
};
env->RegisterNatives(JVMCI::clazz(), JVMCI_native_methods, 1);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
guarantee(false, "");
}
register_natives_for_class(env, NULL, "jdk/vm/ci/hotspot/CompilerToVM", CompilerToVM_nmethods, 1);
register_natives_for_class(env, JVMCI::clazz(), "jdk/vm/ci/runtime/JVMCI", JVMCI_nmethods, 1);
}
}

View file

@ -639,6 +639,7 @@ class JNIJVMCI {
static void initialize_ids(JNIEnv* env);
static void initialize_field_id(JNIEnv* env, jfieldID &dest_offset, jclass klass, const char* klass_name, const char* name, const char* signature, bool static_field);
static void register_natives(JNIEnv* env);
static jobject resolve_handle(JVMCIObject obj) { return obj.as_jobject(); }
static JVMCIObject wrap(jobject obj) { return JVMCIObject(obj, false); }

View file

@ -25,9 +25,12 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/oopStorage.inline.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "jvmci/jniAccessMark.inline.hpp"
#include "jvmci/jvmciCompilerToVM.hpp"
#include "jvmci/jvmciRuntime.hpp"
#include "jvmci/metadataHandles.hpp"
#include "logging/log.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.hpp"
@ -35,11 +38,13 @@
#include "oops/method.inline.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1ThreadLocalData.hpp"
@ -705,6 +710,156 @@ void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) {
}
}
JVMCIRuntime::JVMCIRuntime(int id) {
_init_state = uninitialized;
_shared_library_javavm = NULL;
_id = id;
_metadata_handles = new MetadataHandles();
TRACE_jvmci_1("created new JVMCI runtime %d (" PTR_FORMAT ")", id, p2i(this));
}
// Handles to objects in the Hotspot heap.
static OopStorage* object_handles() {
return OopStorageSet::vm_global();
}
jobject JVMCIRuntime::make_global(const Handle& obj) {
assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
assert(oopDesc::is_oop(obj()), "not an oop");
oop* ptr = object_handles()->allocate();
jobject res = NULL;
if (ptr != NULL) {
assert(*ptr == NULL, "invariant");
NativeAccess<>::oop_store(ptr, obj());
res = reinterpret_cast<jobject>(ptr);
} else {
vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR,
"Cannot create JVMCI oop handle");
}
MutexLocker ml(JVMCI_lock);
return res;
}
void JVMCIRuntime::destroy_global(jobject handle) {
// Assert before nulling out, for better debugging.
assert(is_global_handle(handle), "precondition");
oop* oop_ptr = reinterpret_cast<oop*>(handle);
NativeAccess<>::oop_store(oop_ptr, (oop)NULL);
object_handles()->release(oop_ptr);
MutexLocker ml(JVMCI_lock);
}
bool JVMCIRuntime::is_global_handle(jobject handle) {
const oop* ptr = reinterpret_cast<oop*>(handle);
return object_handles()->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY;
}
jmetadata JVMCIRuntime::allocate_handle(const methodHandle& handle) {
MutexLocker ml(JVMCI_lock);
return _metadata_handles->allocate_handle(handle);
}
jmetadata JVMCIRuntime::allocate_handle(const constantPoolHandle& handle) {
MutexLocker ml(JVMCI_lock);
return _metadata_handles->allocate_handle(handle);
}
void JVMCIRuntime::release_handle(jmetadata handle) {
MutexLocker ml(JVMCI_lock);
_metadata_handles->chain_free_list(handle);
}
JNIEnv* JVMCIRuntime::init_shared_library_javavm() {
JavaVM* javaVM = (JavaVM*) _shared_library_javavm;
if (javaVM == NULL) {
MutexLocker locker(JVMCI_lock);
// Check again under JVMCI_lock
javaVM = (JavaVM*) _shared_library_javavm;
if (javaVM != NULL) {
return NULL;
}
char* sl_path;
void* sl_handle = JVMCI::get_shared_library(sl_path, true);
jint (*JNI_CreateJavaVM)(JavaVM **pvm, void **penv, void *args);
typedef jint (*JNI_CreateJavaVM_t)(JavaVM **pvm, void **penv, void *args);
JNI_CreateJavaVM = CAST_TO_FN_PTR(JNI_CreateJavaVM_t, os::dll_lookup(sl_handle, "JNI_CreateJavaVM"));
if (JNI_CreateJavaVM == NULL) {
vm_exit_during_initialization("Unable to find JNI_CreateJavaVM", sl_path);
}
ResourceMark rm;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.ignoreUnrecognized = JNI_TRUE;
JavaVMOption options[1];
jlong javaVM_id = 0;
// Protocol: JVMCI shared library JavaVM should support a non-standard "_javavm_id"
// option whose extraInfo info field is a pointer to which a unique id for the
// JavaVM should be written.
options[0].optionString = (char*) "_javavm_id";
options[0].extraInfo = &javaVM_id;
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = sizeof(options) / sizeof(JavaVMOption);
JNIEnv* env = NULL;
int result = (*JNI_CreateJavaVM)(&javaVM, (void**) &env, &vm_args);
if (result == JNI_OK) {
guarantee(env != NULL, "missing env");
_shared_library_javavm = javaVM;
TRACE_jvmci_1("created JavaVM[%ld]@" PTR_FORMAT " for JVMCI runtime %d", javaVM_id, p2i(javaVM), _id);
return env;
} else {
vm_exit_during_initialization(err_msg("JNI_CreateJavaVM failed with return value %d", result), sl_path);
}
}
return NULL;
}
void JVMCIRuntime::init_JavaVM_info(jlongArray info, JVMCI_TRAPS) {
if (info != NULL) {
typeArrayOop info_oop = (typeArrayOop) JNIHandles::resolve(info);
if (info_oop->length() < 4) {
JVMCI_THROW_MSG(ArrayIndexOutOfBoundsException, err_msg("%d < 4", info_oop->length()));
}
JavaVM* javaVM = (JavaVM*) _shared_library_javavm;
info_oop->long_at_put(0, (jlong) (address) javaVM);
info_oop->long_at_put(1, (jlong) (address) javaVM->functions->reserved0);
info_oop->long_at_put(2, (jlong) (address) javaVM->functions->reserved1);
info_oop->long_at_put(3, (jlong) (address) javaVM->functions->reserved2);
}
}
#define JAVAVM_CALL_BLOCK \
guarantee(thread != NULL && _shared_library_javavm != NULL, "npe"); \
ThreadToNativeFromVM ttnfv(thread); \
JavaVM* javavm = (JavaVM*) _shared_library_javavm;
jint JVMCIRuntime::AttachCurrentThread(JavaThread* thread, void **penv, void *args) {
JAVAVM_CALL_BLOCK
return javavm->AttachCurrentThread(penv, args);
}
jint JVMCIRuntime::AttachCurrentThreadAsDaemon(JavaThread* thread, void **penv, void *args) {
JAVAVM_CALL_BLOCK
return javavm->AttachCurrentThreadAsDaemon(penv, args);
}
jint JVMCIRuntime::DetachCurrentThread(JavaThread* thread) {
JAVAVM_CALL_BLOCK
return javavm->DetachCurrentThread();
}
jint JVMCIRuntime::GetEnv(JavaThread* thread, void **penv, jint version) {
JAVAVM_CALL_BLOCK
return javavm->GetEnv(penv, version);
}
#undef JAVAVM_CALL_BLOCK \
void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
if (is_HotSpotJVMCIRuntime_initialized()) {
if (JVMCIENV->is_hotspot() && UseJVMCINativeLibrary) {
@ -718,29 +873,32 @@ void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
JVMCIObject result = JVMCIENV->call_HotSpotJVMCIRuntime_runtime(JVMCI_CHECK);
_HotSpotJVMCIRuntime_instance = JVMCIENV->make_global(result);
JVMCI::_is_initialized = true;
}
void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
assert(this != NULL, "sanity");
// Check first without JVMCI_lock
if (_initialized) {
if (_init_state == fully_initialized) {
return;
}
MutexLocker locker(JVMCI_lock);
// Check again under JVMCI_lock
if (_initialized) {
if (_init_state == fully_initialized) {
return;
}
while (_being_initialized) {
while (_init_state == being_initialized) {
TRACE_jvmci_1("waiting for initialization of JVMCI runtime %d", _id);
JVMCI_lock->wait();
if (_initialized) {
if (_init_state == fully_initialized) {
TRACE_jvmci_1("done waiting for initialization of JVMCI runtime %d", _id);
return;
}
}
_being_initialized = true;
TRACE_jvmci_1("initializing JVMCI runtime %d", _id);
_init_state = being_initialized;
{
MutexUnlocker unlock(JVMCI_lock);
@ -759,6 +917,11 @@ void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
fatal("JNI exception during init");
}
}
if (!JVMCIENV->is_hotspot()) {
JNIAccessMark jni(JVMCIENV, THREAD);
JNIJVMCI::register_natives(jni.env());
}
create_jvmci_primitive_type(T_BOOLEAN, JVMCI_CHECK_EXIT_((void)0));
create_jvmci_primitive_type(T_BYTE, JVMCI_CHECK_EXIT_((void)0));
create_jvmci_primitive_type(T_CHAR, JVMCI_CHECK_EXIT_((void)0));
@ -774,8 +937,8 @@ void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
}
}
_initialized = true;
_being_initialized = false;
_init_state = fully_initialized;
TRACE_jvmci_1("initialized JVMCI runtime %d", _id);
JVMCI_lock->notify_all();
}
@ -817,8 +980,7 @@ JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
return _HotSpotJVMCIRuntime_instance;
}
// private void CompilerToVM.registerNatives()
// private static void CompilerToVM.registerNatives()
JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass))
JNI_JVMCIENV(thread, env);
@ -854,16 +1016,17 @@ JVM_END
void JVMCIRuntime::shutdown() {
if (is_HotSpotJVMCIRuntime_initialized()) {
_shutdown_called = true;
THREAD_JVMCIENV(JavaThread::current());
if (_HotSpotJVMCIRuntime_instance.is_non_null()) {
TRACE_jvmci_1("shutting down HotSpotJVMCIRuntime for JVMCI runtime %d", _id);
JVMCIEnv __stack_jvmci_env__(JavaThread::current(), _HotSpotJVMCIRuntime_instance.is_hotspot(), __FILE__, __LINE__);
JVMCIEnv* JVMCIENV = &__stack_jvmci_env__;
JVMCIENV->call_HotSpotJVMCIRuntime_shutdown(_HotSpotJVMCIRuntime_instance);
TRACE_jvmci_1("shut down HotSpotJVMCIRuntime for JVMCI runtime %d", _id);
}
}
void JVMCIRuntime::bootstrap_finished(TRAPS) {
if (is_HotSpotJVMCIRuntime_initialized()) {
if (_HotSpotJVMCIRuntime_instance.is_non_null()) {
THREAD_JVMCIENV(JavaThread::current());
JVMCIENV->call_HotSpotJVMCIRuntime_bootstrapFinished(_HotSpotJVMCIRuntime_instance, JVMCIENV);
}
@ -1290,10 +1453,10 @@ void JVMCIRuntime::compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, c
if (compiler->is_bootstrapping() && is_osr) {
// no OSR compilations during bootstrap - the compiler is just too slow at this point,
// and we know that there are no endless loops
compile_state->set_failure(true, "No OSR during boostrap");
compile_state->set_failure(true, "No OSR during bootstrap");
return;
}
if (JVMCI::shutdown_called()) {
if (JVMCI::in_shutdown()) {
compile_state->set_failure(false, "Avoiding compilation during shutdown");
return;
}
@ -1521,3 +1684,14 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
return result;
}
bool JVMCIRuntime::trace_prefix(int level) {
Thread* thread = Thread::current_or_null_safe();
if (thread != NULL) {
ResourceMark rm;
tty->print("JVMCITrace-%d[%s]:%*c", level, thread == NULL ? "?" : thread->name(), level, ' ');
} else {
tty->print("JVMCITrace-%d[?]:%*c", level, level, ' ');
}
return true;
}

View file

@ -28,10 +28,12 @@
#include "jvmci/jvmci.hpp"
#include "jvmci/jvmciExceptions.hpp"
#include "jvmci/jvmciObject.hpp"
#include "utilities/linkedlist.hpp"
class JVMCIEnv;
class JVMCICompiler;
class JVMCICompileState;
class MetadataHandles;
// Encapsulates the JVMCI metadata for an nmethod.
// JVMCINMethodData objects are inlined into nmethods
@ -86,6 +88,7 @@ public:
// A top level class that represents an initialized JVMCI runtime.
// There is one instance of this class per HotSpotJVMCIRuntime object.
class JVMCIRuntime: public CHeapObj<mtJVMCI> {
friend class JVMCI;
public:
// Constants describing whether JVMCI wants to be able to adjust the compilation
// level selected for a method by the VM compilation policy and if so, based on
@ -97,12 +100,28 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
};
private:
volatile bool _being_initialized;
volatile bool _initialized;
enum InitState {
uninitialized,
being_initialized,
fully_initialized
};
// Initialization state of this JVMCIRuntime.
InitState _init_state;
JVMCIObject _HotSpotJVMCIRuntime_instance;
bool _shutdown_called;
// Result of calling JNI_CreateJavaVM in the JVMCI shared library.
// Must only be modified under JVMCI_lock.
volatile JavaVM* _shared_library_javavm;
// The HotSpot heap based runtime will have an id of -1 and the
// JVMCI shared library runtime will have an id of 0.
int _id;
// Handles to Metadata objects.
MetadataHandles* _metadata_handles;
JVMCIObject create_jvmci_primitive_type(BasicType type, JVMCI_TRAPS);
@ -131,44 +150,74 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
constantTag tag);
public:
JVMCIRuntime() {
_initialized = false;
_being_initialized = false;
_shutdown_called = false;
}
JVMCIRuntime(int id);
/**
* Compute offsets and construct any state required before executing JVMCI code.
*/
int id() const { return _id; }
// Ensures that a JVMCI shared library JavaVM exists for this runtime.
// If the JavaVM was created by this call, then the thread-local JNI
// interface pointer for the JavaVM is returned otherwise NULL is returned.
JNIEnv* init_shared_library_javavm();
// Determines if the JVMCI shared library JavaVM exists for this runtime.
bool has_shared_library_javavm() { return _shared_library_javavm != NULL; }
// Copies info about the JVMCI shared library JavaVM associated with this
// runtime into `info` as follows:
// {
// javaVM, // the {@code JavaVM*} value
// javaVM->functions->reserved0,
// javaVM->functions->reserved1,
// javaVM->functions->reserved2
// }
void init_JavaVM_info(jlongArray info, JVMCI_TRAPS);
// Wrappers for calling Invocation Interface functions on the
// JVMCI shared library JavaVM associated with this runtime.
// These wrappers ensure all required thread state transitions are performed.
jint AttachCurrentThread(JavaThread* thread, void **penv, void *args);
jint AttachCurrentThreadAsDaemon(JavaThread* thread, void **penv, void *args);
jint DetachCurrentThread(JavaThread* thread);
jint GetEnv(JavaThread* thread, void **penv, jint version);
// Compute offsets and construct any state required before executing JVMCI code.
void initialize(JVMCIEnv* jvmciEnv);
/**
* Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary
*/
// Allocation and management of JNI global object handles.
jobject make_global(const Handle& obj);
void destroy_global(jobject handle);
bool is_global_handle(jobject handle);
// Allocation and management of metadata handles.
jmetadata allocate_handle(const methodHandle& handle);
jmetadata allocate_handle(const constantPoolHandle& handle);
void release_handle(jmetadata handle);
// Gets the HotSpotJVMCIRuntime instance for this runtime,
// initializing it first if necessary.
JVMCIObject get_HotSpotJVMCIRuntime(JVMCI_TRAPS);
bool is_HotSpotJVMCIRuntime_initialized() {
return _HotSpotJVMCIRuntime_instance.is_non_null();
}
/**
* Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime()
*/
// Gets the current HotSpotJVMCIRuntime instance for this runtime which
// may be a "null" JVMCIObject value.
JVMCIObject probe_HotSpotJVMCIRuntime() {
return _HotSpotJVMCIRuntime_instance;
}
// Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime()
void initialize_JVMCI(JVMCI_TRAPS);
/**
* Explicitly initialize HotSpotJVMCIRuntime itself
*/
// Explicitly initialize HotSpotJVMCIRuntime itself
void initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS);
void call_getCompiler(TRAPS);
// Shuts down this runtime by calling HotSpotJVMCIRuntime.shutdown().
void shutdown();
bool shutdown_called() {
return _shutdown_called;
}
void bootstrap_finished(TRAPS);
// Look up a klass by name from a particular class loader (the accessor's).
@ -235,9 +284,7 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
char* speculations,
int speculations_len);
/**
* Exits the VM due to an unexpected exception.
*/
// Exits the VM due to an unexpected exception.
static void exit_on_pending_exception(JVMCIEnv* JVMCIENV, const char* message);
static void describe_pending_hotspot_exception(JavaThread* THREAD, bool clear);
@ -339,6 +386,11 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
// Test only function
static jint test_deoptimize_call_int(JavaThread* thread, int value);
// Emits the following on tty:
// "JVMCITrace-" <level> "[" <current thread name> "]:" <padding of width `level`>
// Returns true.
static bool trace_prefix(int level);
};
// Tracing macros.
@ -349,10 +401,11 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
#define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else
#define IF_TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5)) ; else
#define TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1 && (tty->print(PTR_FORMAT " JVMCITrace-1: ", p2i(JavaThread::current())), true))) ; else tty->print_cr
#define TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2 && (tty->print(PTR_FORMAT " JVMCITrace-2: ", p2i(JavaThread::current())), true))) ; else tty->print_cr
#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(PTR_FORMAT " JVMCITrace-3: ", p2i(JavaThread::current())), true))) ; else tty->print_cr
#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(PTR_FORMAT " JVMCITrace-4: ", p2i(JavaThread::current())), true))) ; else tty->print_cr
#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(PTR_FORMAT " JVMCITrace-5: ", p2i(JavaThread::current())), true))) ; else tty->print_cr
#define TRACE_jvmci_(n) if (!(JVMCITraceLevel >= n && JVMCIRuntime::trace_prefix(n))) ; else tty->print_cr
#define TRACE_jvmci_1 TRACE_jvmci_(1)
#define TRACE_jvmci_2 TRACE_jvmci_(2)
#define TRACE_jvmci_3 TRACE_jvmci_(3)
#define TRACE_jvmci_4 TRACE_jvmci_(4)
#define TRACE_jvmci_5 TRACE_jvmci_(5)
#endif // SHARE_JVMCI_JVMCIRUNTIME_HPP

View file

@ -22,19 +22,17 @@
*/
#include "precompiled.hpp"
#include "jvmci/metadataHandleBlock.hpp"
#include "jvmci/metadataHandles.hpp"
#include "runtime/atomic.hpp"
MetadataHandleBlock* MetadataHandleBlock::_last = NULL;
intptr_t MetadataHandleBlock::_free_list = 0;
int MetadataHandleBlock::_allocate_before_rebuild = 0;
jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) {
jmetadata MetadataHandles::allocate_metadata_handle(Metadata* obj) {
assert(obj->is_valid() && obj->is_metadata(), "must be");
if (_last == NULL) {
if (_head == NULL) {
// This is the first allocation.
_last = this;
_head = new MetadataHandleBlock();
_last = _head;
_num_blocks++;
}
HandleRecord* handle = get_handle();
@ -47,7 +45,7 @@ jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) {
return (jmetadata) handle;
}
// Check if unused block follow last
// Check if an unused block follows last
if (_last->_next != NULL) {
// update last and retry
_last = _last->_next;
@ -59,20 +57,20 @@ jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) {
rebuild_free_list(); // updates _allocate_before_rebuild counter
} else {
// Append new block
// This can block, but the caller has a metadata handle around this object.
_last->_next = allocate_block();
_last->_next = new MetadataHandleBlock();
_last = _last->_next;
_allocate_before_rebuild--;
_num_blocks++;
}
return allocate_metadata_handle(obj); // retry
}
void MetadataHandleBlock::rebuild_free_list() {
void MetadataHandles::rebuild_free_list() {
assert(_allocate_before_rebuild == 0 && _free_list == 0, "just checking");
int free = 0;
int blocks = 0;
for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) {
for (MetadataHandleBlock* current = _head; current != NULL; current = current->_next) {
for (int index = 0; index < current->_top; index++) {
HandleRecord* handle = &(current->_handles)[index];
if (handle->value() == NULL) {
@ -82,34 +80,48 @@ void MetadataHandleBlock::rebuild_free_list() {
}
}
// we should not rebuild free list if there are unused handles at the end
assert(current->_top == block_size_in_handles, "just checking");
assert(current->_top == MetadataHandleBlock::block_size_in_handles, "just checking");
blocks++;
}
assert(_num_blocks == blocks, "%d != %d", _num_blocks, blocks);
assert(_num_free_handles == free, "%d != %d", _num_free_handles, free);
// Heuristic: if more than half of the handles are NOT free we rebuild next time
// as well, otherwise we append a corresponding number of new blocks before
// attempting a free list rebuild again.
int total = blocks * block_size_in_handles;
int total = blocks * MetadataHandleBlock::block_size_in_handles;
int extra = total - 2*free;
if (extra > 0) {
// Not as many free handles as we would like - compute number of new blocks to append
_allocate_before_rebuild = (extra + block_size_in_handles - 1) / block_size_in_handles;
_allocate_before_rebuild = (extra + MetadataHandleBlock::block_size_in_handles - 1) / MetadataHandleBlock::block_size_in_handles;
}
}
void MetadataHandleBlock::metadata_do(void f(Metadata*)) {
for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) {
void MetadataHandles::clear() {
_free_list = 0;
_last = _head;
if (_head != NULL) {
for (MetadataHandleBlock* block = _head; block != NULL; block = block->_next) {
block->_top = 0;
}
}
_num_handles = 0;
_num_free_handles = 0;
}
void MetadataHandles::metadata_do(void f(Metadata*)) {
for (MetadataHandleBlock* current = _head; current != NULL; current = current->_next) {
for (int index = 0; index < current->_top; index++) {
HandleRecord* root = &(current->_handles)[index];
Metadata* value = root->value();
// traverse heap pointers only, not deleted handles or free list
// pointers
if (value != NULL && ((intptr_t) value & ptr_tag) == 0) {
assert(value->is_valid(), "invalid metadata %s", get_name(index));
assert(value->is_valid(), "invalid metadata %s", current->get_name(index));
f(value);
}
}
// the next handle block is valid only if current block is full
if (current->_top < block_size_in_handles) {
if (current->_top < MetadataHandleBlock::block_size_in_handles) {
break;
}
}
@ -117,8 +129,8 @@ void MetadataHandleBlock::metadata_do(void f(Metadata*)) {
// Visit any live metadata handles and clean them up. Since clearing of these handles is driven by
// weak references they will be cleared at some point in the future when the reference cleaning logic is run.
void MetadataHandleBlock::do_unloading() {
for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) {
void MetadataHandles::do_unloading() {
for (MetadataHandleBlock* current = _head; current != NULL; current = current->_next) {
for (int index = 0; index < current->_top; index++) {
HandleRecord* handle = &(current->_handles)[index];
Metadata* value = handle->value();
@ -152,7 +164,7 @@ void MetadataHandleBlock::do_unloading() {
}
}
// the next handle block is valid only if current block is full
if (current->_top < block_size_in_handles) {
if (current->_top < MetadataHandleBlock::block_size_in_handles) {
break;
}
}

View file

@ -21,8 +21,8 @@
* questions.
*/
#ifndef SHARE_JVMCI_METADATAHANDLEBLOCK_HPP
#define SHARE_JVMCI_METADATAHANDLEBLOCK_HPP
#ifndef SHARE_JVMCI_METADATAHANDLES_HPP
#define SHARE_JVMCI_METADATAHANDLES_HPP
#include "oops/constantPool.hpp"
#include "oops/metadata.hpp"
@ -72,22 +72,15 @@ struct _jmetadata {
typedef struct _jmetadata HandleRecord;
typedef struct _jmetadata *jmetadata;
class MetadataHandles;
// JVMCI maintains direct references to metadata. To make these references safe in the face of
// class redefinition, they are held in handles so they can be scanned during GC. They are
// managed in a cooperative way between the Java code and HotSpot. A handle is filled in and
// passed back to the Java code which is responsible for setting the handle to NULL when it
// is no longer in use. This is done by jdk.vm.ci.hotspot.HandleCleaner. The
// rebuild_free_list function notices when the handle is clear and reclaims it for re-use.
class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
friend class MetadataHandles;
private:
enum SomeConstants {
block_size_in_handles = 32, // Number of handles per handle block
ptr_tag = 1,
ptr_mask = ~((intptr_t)ptr_tag)
block_size_in_handles = 32 // Number of handles per handle block
};
// Free handles always have their low bit set so those pointers can
// be distinguished from handles which are in use. The last handle
// on the free list has a NULL pointer with the tag bit set, so it's
@ -98,12 +91,6 @@ class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
int _top; // Index of next unused handle
MetadataHandleBlock* _next; // Link to next block
// The following instance variables are only used by the first block in a chain.
// Having two types of blocks complicates the code and the space overhead is negligible.
static MetadataHandleBlock* _last; // Last block in use
static intptr_t _free_list; // Handle free list
static int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list
MetadataHandleBlock() {
_top = 0;
_next = NULL;
@ -121,20 +108,42 @@ class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
return "<missing>";
#endif
}
};
static HandleRecord* get_free_handle() {
assert(_free_list != 0, "should check before calling");
// JVMCI maintains direct references to metadata. To make these references safe in the face of
// class redefinition, they are held in handles so they can be scanned during GC. They are
// managed in a cooperative way between the Java code and HotSpot. A handle is filled in and
// passed back to the Java code which is responsible for setting the handle to NULL when it
// is no longer in use. This is done by jdk.vm.ci.hotspot.HandleCleaner. The
// rebuild_free_list function notices when the handle is clear and reclaims it for re-use.
class MetadataHandles : public CHeapObj<mtJVMCI> {
private:
enum SomeConstants {
ptr_tag = 1,
ptr_mask = ~((intptr_t)ptr_tag)
};
MetadataHandleBlock* _head; // First block
MetadataHandleBlock* _last; // Last block in use
intptr_t _free_list; // Handle free list
int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list
int _num_blocks; // Number of blocks
int _num_handles;
int _num_free_handles;
HandleRecord* get_free_handle() {
HandleRecord* handle = (HandleRecord*) (_free_list & ptr_mask);
_free_list = (ptr_mask & (intptr_t) (handle->value()));
assert(_free_list != ptr_tag, "should be null");
handle->set_value(NULL);
_num_free_handles--;
return handle;
}
static HandleRecord* get_handle() {
HandleRecord* get_handle() {
assert(_last != NULL, "sanity");
// Try last block
if (_last->_top < block_size_in_handles) {
if (_last->_top < MetadataHandleBlock::block_size_in_handles) {
_num_handles++;
return &(_last->_handles)[_last->_top++];
} else if (_free_list != 0) {
// Try free list
@ -148,23 +157,39 @@ class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
jmetadata allocate_metadata_handle(Metadata* metadata);
public:
MetadataHandles() {
_head = NULL;
_last = NULL;
_free_list = 0;
_allocate_before_rebuild = 0;
_num_blocks = 0;
_num_handles = 0;
_num_free_handles = 0;
}
int num_handles() const { return _num_handles; }
int num_free_handles() const { return _num_free_handles; }
int num_blocks() const { return _num_blocks; }
jmetadata allocate_handle(const methodHandle& handle) { return allocate_metadata_handle(handle()); }
jmetadata allocate_handle(const constantPoolHandle& handle) { return allocate_metadata_handle(handle()); }
static MetadataHandleBlock* allocate_block() { return new MetadataHandleBlock(); }
// Adds `handle` to the free list in this block
static void chain_free_list(HandleRecord* handle) {
// Adds `handle` to the free list
void chain_free_list(HandleRecord* handle) {
handle->set_value((Metadata*) (ptr_tag | _free_list));
#ifdef METADATA_TRACK_NAMES
handle->set_name(NULL);
#endif
_free_list = (intptr_t) handle;
_num_free_handles++;
}
// Clears all handles without releasing any handle memory.
void clear();
void metadata_do(void f(Metadata*));
void do_unloading();
};
#endif // SHARE_JVMCI_METADATAHANDLEBLOCK_HPP
#endif // SHARE_JVMCI_METADATAHANDLES_HPP

View file

@ -65,8 +65,8 @@ final class HandleCleaner extends Cleaner {
CompilerToVM.compilerToVM().deleteGlobalHandle(handle);
} else {
// Setting the target of a jmetadata handle to 0 enables
// the handle to be reused. See MetadataHandleBlock in
// jvmciRuntime.cpp for more info.
// the handle to be reused. See MetadataHandles in
// metadataHandles.hpp for more info.
long value = UNSAFE.getLong(null, handle);
UNSAFE.compareAndSetLong(null, handle, value, 0);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -37,6 +37,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -210,6 +211,15 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
return o.toString();
}
/**
* Set of recognized {@code "jvmci.*"} system properties. Entries not associated with an
* {@link Option} have this object as their value.
*/
static final Map<String, Object> options = new HashMap<>();
static {
options.put("jvmci.class.path.append", options);
}
/**
* A list of all supported JVMCI options.
*/
@ -245,7 +255,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
private final Class<?> type;
@NativeImageReinitialize private Object value;
private final Object defaultValue;
private boolean isDefault;
private boolean isDefault = true;
private final String[] helpLines;
Option(Class<?> type, Object defaultValue, String... helpLines) {
@ -253,12 +263,13 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
this.type = type;
this.defaultValue = defaultValue;
this.helpLines = helpLines;
Object existing = options.put(getPropertyName(), this);
assert existing == null : getPropertyName();
}
@SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
private Object getValue() {
if (value == null) {
String propertyValue = Services.getSavedProperty(getPropertyName());
private void init(String propertyValue) {
assert value == null : "cannot re-initialize " + name();
if (propertyValue == null) {
this.value = defaultValue == null ? NULL_VALUE : defaultValue;
this.isDefault = true;
@ -273,7 +284,16 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
this.isDefault = false;
}
}
return value == NULL_VALUE ? null : value;
@SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
private Object getValue() {
if (value == NULL_VALUE) {
return null;
}
if (value == null) {
return defaultValue;
}
return value;
}
/**
@ -334,6 +354,61 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
}
}
}
/**
* Compute string similarity based on Dice's coefficient.
*
* Ported from str_similar() in globals.cpp.
*/
static float stringSimiliarity(String str1, String str2) {
int hit = 0;
for (int i = 0; i < str1.length() - 1; ++i) {
for (int j = 0; j < str2.length() - 1; ++j) {
if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) {
++hit;
break;
}
}
}
return 2.0f * hit / (str1.length() + str2.length());
}
private static final float FUZZY_MATCH_THRESHOLD = 0.7F;
/**
* Parses all system properties starting with {@value #JVMCI_OPTION_PROPERTY_PREFIX} and
* initializes the options based on their values.
*/
static void parse() {
Map<String, String> savedProps = jdk.vm.ci.services.Services.getSavedProperties();
for (Map.Entry<String, String> e : savedProps.entrySet()) {
String name = e.getKey();
if (name.startsWith(Option.JVMCI_OPTION_PROPERTY_PREFIX)) {
Object value = options.get(name);
if (value == null) {
List<String> matches = new ArrayList<>();
for (String pn : options.keySet()) {
float score = stringSimiliarity(pn, name);
if (score >= FUZZY_MATCH_THRESHOLD) {
matches.add(pn);
}
}
Formatter msg = new Formatter();
msg.format("Could not find option %s", name);
if (!matches.isEmpty()) {
msg.format("%nDid you mean one of the following?");
for (String match : matches) {
msg.format("%n %s=<value>", match);
}
}
throw new IllegalArgumentException(msg.toString());
} else if (value instanceof Option) {
Option option = (Option) value;
option.init(e.getValue());
}
}
}
}
}
private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
@ -454,6 +529,9 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
System.setErr(vmLogStream);
}
// Initialize the Option values.
Option.parse();
String hostArchitecture = config.getHostArchitectureName();
HotSpotJVMCIBackendFactory factory;
@ -712,11 +790,18 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
return hsResult;
}
/**
* Guard to ensure shut down actions are performed at most once.
*/
private boolean isShutdown;
/**
* Shuts down the runtime.
*/
@VMEntryPoint
private void shutdown() throws Exception {
private synchronized void shutdown() throws Exception {
if (!isShutdown) {
isShutdown = true;
// Cleaners are normally only processed when a new Cleaner is
// instantiated so process all remaining cleaners now.
Cleaner.clean();
@ -725,6 +810,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
vmEventListener.notifyShutdown();
}
}
}
/**
* Notify on completion of a bootstrap.
@ -914,8 +1000,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
* </pre>
*
* The implementation of the native {@code JCompile.compile0} method would be in the JVMCI
* shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0}
* implementation will be exported as the following JNI-compatible symbol:
* shared library that contains the JVMCI compiler. The {@code JCompile.compile0} implementation
* must be exported as the following JNI-compatible symbol:
*
* <pre>
* Java_com_jcompile_JCompile_compile0
@ -926,9 +1012,18 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
* @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions"
*
*
* @return an array of 4 longs where the first value is the {@code JavaVM*} value representing
* the Java VM in the JVMCI shared library, and the remaining values are the first 3
* pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface})
* @return info about the Java VM in the JVMCI shared library {@code JavaVM*}. The info is
* encoded in a long array as follows:
*
* <pre>
* long[] info = {
* javaVM, // the {@code JavaVM*} value
* javaVM->functions->reserved0,
* javaVM->functions->reserved1,
* javaVM->functions->reserved2
* }
* </pre>
*
* @throws NullPointerException if {@code clazz == null}
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
@ -1017,6 +1112,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the peer runtime has not been initialized or there is an
* error while trying to attach the thread
* @throws ArrayIndexOutOfBoundsException if {@code javaVMInfo} is non-null and is shorter than
* the length of the array returned by {@link #registerNativeMethods}
*/
public boolean attachCurrentThread(boolean asDaemon) {
return compilerToVm.attachCurrentThread(asDaemon);