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 // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown
// to avoid deadlock between compiler thread(s) and threads run at shutdown // to avoid deadlock between compiler thread(s) and threads run at shutdown
// such as the DestroyJavaVM thread. // such as the DestroyJavaVM thread.
if (JVMCI::shutdown_called()) { if (JVMCI::in_shutdown()) {
blocking = false; blocking = false;
} }
} }
@ -2150,16 +2150,22 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
TraceTime t1("compilation", &time); TraceTime t1("compilation", &time);
EventCompilation event; EventCompilation event;
JVMCICompileState compile_state(task); 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 // Skip redefined methods
if (compile_state.target_method_is_old()) {
failure_reason = "redefined method"; failure_reason = "redefined method";
retry_message = "not retryable"; retry_message = "not retryable";
compilable = ciEnv::MethodCompilable_never; compilable = ciEnv::MethodCompilable_never;
} else { } else {
JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__); JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__);
methodHandle method(thread, target_handle); 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 = compile_state.failure_reason();
failure_reason_on_C_heap = compile_state.failure_reason_on_C_heap(); 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). // to a GC in the shared library).
class JNIAccessMark : public StackObj { class JNIAccessMark : public StackObj {
private: private:
ThreadToNativeFromVM ttnfv; ThreadToNativeFromVM _ttnfv;
HandleMark hm; HandleMark _hm;
JNIEnv* _env; JNIEnv* _env;
public: public:
inline JNIAccessMark(JVMCIEnv* jvmci_env) : inline JNIAccessMark(JVMCIEnv* jvmci_env, JavaThread* thread=JavaThread::current()) :
ttnfv(JavaThread::current()), hm(JavaThread::current()) { _ttnfv(thread), _hm(thread) {
_env = jvmci_env->_env; _env = jvmci_env->_env;
} }
JNIEnv* env() const { return _env; } JNIEnv* env() const { return _env; }

View file

@ -24,17 +24,19 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.hpp"
#include "gc/shared/oopStorage.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "jvmci/jvmci.hpp" #include "jvmci/jvmci.hpp"
#include "jvmci/jvmciJavaClasses.hpp" #include "jvmci/jvmciJavaClasses.hpp"
#include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciRuntime.hpp"
#include "jvmci/metadataHandleBlock.hpp" #include "jvmci/metadataHandles.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
MetadataHandleBlock* JVMCI::_metadata_handles = NULL;
JVMCIRuntime* JVMCI::_compiler_runtime = NULL; JVMCIRuntime* JVMCI::_compiler_runtime = NULL;
JVMCIRuntime* JVMCI::_java_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; void jvmci_vmStructs_init() NOT_DEBUG_RETURN;
@ -50,6 +52,40 @@ bool JVMCI::can_initialize_JVMCI() {
return true; 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) { void JVMCI::initialize_compiler(TRAPS) {
if (JVMCILibDumpJNIConfig) { if (JVMCILibDumpJNIConfig) {
JNIJVMCI::initialize_ids(NULL); JNIJVMCI::initialize_ids(NULL);
@ -61,93 +97,57 @@ void JVMCI::initialize_compiler(TRAPS) {
void JVMCI::initialize_globals() { void JVMCI::initialize_globals() {
jvmci_vmStructs_init(); jvmci_vmStructs_init();
_metadata_handles = MetadataHandleBlock::allocate_block();
if (UseJVMCINativeLibrary) { if (UseJVMCINativeLibrary) {
// There are two runtimes. // There are two runtimes.
_compiler_runtime = new JVMCIRuntime(); _compiler_runtime = new JVMCIRuntime(0);
_java_runtime = new JVMCIRuntime(); _java_runtime = new JVMCIRuntime(-1);
} else { } else {
// There is only a single runtime // 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*)) { void JVMCI::metadata_do(void f(Metadata*)) {
if (_metadata_handles != NULL) { if (_java_runtime != NULL) {
_metadata_handles->metadata_do(f); _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) { void JVMCI::do_unloading(bool unloading_occurred) {
if (_metadata_handles != NULL && unloading_occurred) { if (unloading_occurred) {
_metadata_handles->do_unloading(); 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() { bool JVMCI::is_compiler_initialized() {
return compiler_runtime()->is_HotSpotJVMCIRuntime_initialized(); return _is_initialized;
} }
void JVMCI::shutdown() { 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) { if (compiler_runtime() != NULL) {
compiler_runtime()->shutdown(); compiler_runtime()->shutdown();
} }
} }
bool JVMCI::shutdown_called() { bool JVMCI::in_shutdown() {
if (compiler_runtime() != NULL) { return _in_shutdown;
return compiler_runtime()->shutdown_called();
}
return false;
} }

View file

@ -45,15 +45,24 @@ class JVMCI : public AllStatic {
friend class JVMCIEnv; friend class JVMCIEnv;
private: private:
// Handles to Metadata objects.
static MetadataHandleBlock* _metadata_handles;
// Access to the HotSpotJVMCIRuntime used by the CompileBroker. // Access to the HotSpotJVMCIRuntime used by the CompileBroker.
static JVMCIRuntime* _compiler_runtime; static JVMCIRuntime* _compiler_runtime;
// Access to the HotSpotJVMCIRuntime used by Java code running on the // True when at least one JVMCIRuntime::initialize_HotSpotJVMCIRuntime()
// HotSpot heap. It will be the same as _compiler_runtime if // execution has completed successfully.
// UseJVMCINativeLibrary is false 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; static JVMCIRuntime* _java_runtime;
public: public:
@ -64,13 +73,20 @@ class JVMCI : public AllStatic {
code_too_large 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 do_unloading(bool unloading_occurred);
static void metadata_do(void f(Metadata*)); static void metadata_do(void f(Metadata*));
static void shutdown(); static void shutdown();
static bool shutdown_called(); // Returns whether JVMCI::shutdown has been called.
static bool in_shutdown();
static bool is_compiler_initialized(); static bool is_compiler_initialized();
@ -83,16 +99,9 @@ class JVMCI : public AllStatic {
static void initialize_compiler(TRAPS); 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; } 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; } 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); (jlong)nanos_to_millis(os::javaTimeNanos() - start), _methods_compiled);
} }
_bootstrapping = false; _bootstrapping = false;
JVMCI::compiler_runtime()->bootstrap_finished(CHECK); JVMCI::java_runtime()->bootstrap_finished(CHECK);
} }
bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) { 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) { if (_bootstrapping) {
// When bootstrapping, the JVMCI compiler can compile its own methods. // When bootstrapping, the JVMCI compiler can compile its own methods.
return false; return false;
} }
if (UseJVMCINativeLibrary) {
JVMCIRuntime* runtime = JVMCI::compiler_runtime(); // This mechanism exists to force compilation of a JVMCI compiler by C1
if (runtime != NULL && runtime->is_HotSpotJVMCIRuntime_initialized()) { // to reduce the compilation time spent on the JVMCI compiler itself. In
JavaThread* thread = JavaThread::current(); // +UseJVMCINativeLibrary mode, the JVMCI compiler is AOT compiled.
HandleMark hm(thread); return false;
THREAD_JVMCIENV(thread); } else {
JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(JVMCIENV); JVMCIRuntime* runtime = JVMCI::java_runtime();
objArrayHandle excludeModules(thread, HotSpotJVMCI::HotSpotJVMCIRuntime::excludeFromJVMCICompilation(JVMCIENV, HotSpotJVMCI::resolve(receiver))); 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()) { if (excludeModules.not_null()) {
ModuleEntry* moduleEntry = method->method_holder()->module(); ModuleEntry* moduleEntry = method->method_holder()->module();
for (int i = 0; i < excludeModules->length(); i++) { for (int i = 0; i < excludeModules->length(); i++) {
@ -133,6 +132,7 @@ bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) {
} }
return false; return false;
} }
}
// Compilation entry point for methods // Compilation entry point for methods
void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) { void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) {

View file

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

View file

@ -77,10 +77,6 @@ bool JVMCICompileState::jvmti_state_changed() const {
return false; 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() { void JVMCIEnv::copy_saved_properties() {
assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image"); 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 // Initialize saved properties in shared library
jclass servicesClass = JNIJVMCI::Services::clazz(); jclass servicesClass = JNIJVMCI::Services::clazz();
jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method(); jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method();
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject()); jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject());
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
jni()->ExceptionDescribe(); 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) { void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
assert(thread != NULL, "npe"); assert(thread != NULL, "npe");
// By default there is only one runtime which is the compiler runtime.
_runtime = JVMCI::compiler_runtime();
_env = NULL; _env = NULL;
_pop_frame_on_close = false; _pop_frame_on_close = false;
_detach_on_close = false; _detach_on_close = false;
if (!UseJVMCINativeLibrary) { if (!UseJVMCINativeLibrary) {
// In HotSpot mode, JNI isn't used at all. // In HotSpot mode, JNI isn't used at all.
_runtime = JVMCI::java_runtime();
_is_hotspot = true; _is_hotspot = true;
return; return;
} }
@ -213,6 +156,8 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
_runtime = JVMCI::java_runtime(); _runtime = JVMCI::java_runtime();
return; return;
} }
_runtime = JVMCI::compiler_runtime();
assert(_runtime != NULL, "npe");
_env = parent_env; _env = parent_env;
return; 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 // Running in JVMCI shared library mode so ensure the shared library
// is loaded and initialized and get a shared library JNIEnv // is loaded and initialized and get a shared library JNIEnv
_is_hotspot = false; _is_hotspot = false;
_env = init_shared_library(thread);
_runtime = JVMCI::compiler_runtime();
_env = _runtime->init_shared_library_javavm();
if (_env != NULL) { if (_env != NULL) {
// Creating the JVMCI shared library VM also attaches the current thread // Creating the JVMCI shared library VM also attaches the current thread
_detach_on_close = true; _detach_on_close = true;
} else { } 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) { if (parent_env != NULL) {
// Even though there's a parent JNI env, there's no guarantee // Even though there's a parent JNI env, there's no guarantee
// it was opened by a JVMCIEnv scope and thus may not have // 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.version = JNI_VERSION_1_2;
attach_args.name = thread->name(); attach_args.name = thread->name();
attach_args.group = NULL; 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); fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name);
} }
_detach_on_close = true; _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(_env != NULL, "missing env");
assert(_throw_to_caller == false, "must be"); assert(_throw_to_caller == false, "must be");
JNIAccessMark jni(this); JNIAccessMark jni(this, thread);
jint result = _env->PushLocalFrame(32); jint result = _env->PushLocalFrame(32);
if (result != JNI_OK) { if (result != JNI_OK) {
char message[256]; 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. // Prints a pending exception (if any) and its stack trace.
void JVMCIEnv::describe_pending_exception(bool clear) { void JVMCIEnv::describe_pending_exception(bool clear) {
Thread* THREAD = Thread::current();
if (!is_hotspot()) { if (!is_hotspot()) {
JNIAccessMark jni(this); JNIAccessMark jni(this);
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
@ -304,7 +252,6 @@ void JVMCIEnv::describe_pending_exception(bool clear) {
} }
} }
} else { } else {
Thread* THREAD = Thread::current();
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
JVMCIRuntime::describe_pending_hotspot_exception((JavaThread*) THREAD, clear); JVMCIRuntime::describe_pending_hotspot_exception((JavaThread*) THREAD, clear);
} }
@ -332,7 +279,7 @@ void JVMCIEnv::translate_hotspot_exception_to_jni_exception(JavaThread* THREAD,
ResourceMark rm; ResourceMark rm;
const char* encoded_throwable_chars = java_lang_String::as_utf8_string(encoded_throwable_string); 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); jobject jni_encoded_throwable_string = jni()->NewStringUTF(encoded_throwable_chars);
jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(), JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(),
@ -368,7 +315,7 @@ JVMCIEnv::~JVMCIEnv() {
} }
if (_detach_on_close) { 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: default:
JVMCI_THROW_MSG_(IllegalArgumentException, "Only boxes for primitive values can be created", JVMCIObject()); JVMCI_THROW_MSG_(IllegalArgumentException, "Only boxes for primitive values can be created", JVMCIObject());
} }
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
oop box = java_lang_boxing_object::create(type, value, CHECK_(JVMCIObject())); oop box = java_lang_boxing_object::create(type, value, CHECK_(JVMCIObject()));
return HotSpotJVMCI::wrap(box); return HotSpotJVMCI::wrap(box);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject box = jni()->NewObjectA(JNIJVMCI::box_class(type), JNIJVMCI::box_constructor(type), value); jobject box = jni()->NewObjectA(JNIJVMCI::box_class(type), JNIJVMCI::box_constructor(type), value);
assert(box != NULL, ""); assert(box != NULL, "");
return wrap(box); 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); vsnprintf(msg, max_msg_size, format, ap);
msg[max_msg_size-1] = '\0'; msg[max_msg_size-1] = '\0';
va_end(ap); va_end(ap);
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
Handle h_loader = Handle(); Handle h_loader = Handle();
Handle h_protection_domain = Handle(); Handle h_protection_domain = Handle();
Exceptions::_throw_msg(THREAD, file, line, vmSymbols::jdk_vm_ci_common_JVMCIError(), msg, h_loader, h_protection_domain); Exceptions::_throw_msg(THREAD, file, line, vmSymbols::jdk_vm_ci_common_JVMCIError(), msg, h_loader, h_protection_domain);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jni()->ThrowNew(JNIJVMCI::JVMCIError::clazz(), msg); jni()->ThrowNew(JNIJVMCI::JVMCIError::clazz(), msg);
} }
} }
@ -735,7 +682,7 @@ void JVMCIEnv::call_HotSpotJVMCIRuntime_shutdown (JVMCIObject runtime) {
JavaValue result(T_VOID); JavaValue result(T_VOID);
JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::shutdown_name(), vmSymbols::void_method_signature(), &jargs, THREAD); JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::shutdown_name(), vmSymbols::void_method_signature(), &jargs, THREAD);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::shutdown_method()); jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::shutdown_method());
} }
if (has_pending_exception()) { 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())); JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::runtime_name(), vmSymbols::runtime_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::runtime_method()); jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::runtime_method());
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); 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())); JavaCalls::call_static(&result, HotSpotJVMCI::JVMCI::klass(), vmSymbols::getRuntime_name(), vmSymbols::getRuntime_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::JVMCI::clazz(), JNIJVMCI::JVMCI::getRuntime_method()); jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::JVMCI::clazz(), JNIJVMCI::JVMCI::getRuntime_method());
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); 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())); JavaCalls::call_virtual(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::getCompiler_name(), vmSymbols::getCompiler_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->CallObjectMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::getCompiler_method()); jobject result = jni()->CallObjectMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::getCompiler_method());
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); return JVMCIObject();
@ -810,7 +757,7 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(JVMCIObject object,
vmSymbols::callToString_signature(), &jargs, CHECK_(JVMCIObject())); vmSymbols::callToString_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::callToString_method(), JNIJVMCI::HotSpotJVMCIRuntime::callToString_method(),
object.as_jobject()); object.as_jobject());
@ -835,7 +782,7 @@ JVMCIObject JVMCIEnv::call_PrimitiveConstant_forTypeChar(jchar kind, jlong value
vmSymbols::forTypeChar_signature(), &jargs, CHECK_(JVMCIObject())); vmSymbols::forTypeChar_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::PrimitiveConstant::clazz(), jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::PrimitiveConstant::clazz(),
JNIJVMCI::PrimitiveConstant::forTypeChar_method(), JNIJVMCI::PrimitiveConstant::forTypeChar_method(),
kind, value); kind, value);
@ -858,7 +805,7 @@ JVMCIObject JVMCIEnv::call_JavaConstant_forFloat(float value, JVMCI_TRAPS) {
vmSymbols::forFloat_signature(), &jargs, CHECK_(JVMCIObject())); vmSymbols::forFloat_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(), jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(),
JNIJVMCI::JavaConstant::forFloat_method(), JNIJVMCI::JavaConstant::forFloat_method(),
value); value);
@ -881,7 +828,7 @@ JVMCIObject JVMCIEnv::call_JavaConstant_forDouble(double value, JVMCI_TRAPS) {
vmSymbols::forDouble_signature(), &jargs, CHECK_(JVMCIObject())); vmSymbols::forDouble_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap((oop) result.get_jobject()); return wrap((oop) result.get_jobject());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(), jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(),
JNIJVMCI::JavaConstant::forDouble_method(), JNIJVMCI::JavaConstant::forDouble_method(),
value); value);
@ -926,7 +873,7 @@ JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci,
HotSpotJVMCI::StackTraceElement::set_lineNumber(this, obj(), line_number); HotSpotJVMCI::StackTraceElement::set_lineNumber(this, obj(), line_number);
return wrap(obj()); return wrap(obj());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject declaring_class = jni()->NewStringUTF(declaring_class_str); jobject declaring_class = jni()->NewStringUTF(declaring_class_str);
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); return JVMCIObject();
@ -978,7 +925,7 @@ JVMCIObject JVMCIEnv::new_HotSpotNmethod(const methodHandle& method, const char*
&jargs, CHECK_(JVMCIObject())); &jargs, CHECK_(JVMCIObject()));
return wrap(obj_h()); return wrap(obj_h());
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject nameStr = name == NULL ? NULL : jni()->NewStringUTF(name); jobject nameStr = name == NULL ? NULL : jni()->NewStringUTF(name);
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); 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) { void JVMCIEnv::destroy_local(JVMCIObject object) {
if (is_hotspot()) { if (is_hotspot()) {
JNIHandles::destroy_local(object.as_jobject()); 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) { const char* JVMCIEnv::klass_name(JVMCIObject object) {
if (is_hotspot()) { if (is_hotspot()) {
return HotSpotJVMCI::resolve(object)->klass()->signature_name(); 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(); Thread* THREAD = Thread::current();
jmetadata handle = JVMCI::allocate_handle(method); jmetadata handle = _runtime->allocate_handle(method);
jboolean exception = false; jboolean exception = false;
if (is_hotspot()) { if (is_hotspot()) {
JavaValue result(T_OBJECT); JavaValue result(T_OBJECT);
@ -1099,13 +1025,13 @@ JVMCIObject JVMCIEnv::get_jvmci_method(const methodHandle& method, JVMCI_TRAPS)
} }
if (exception) { if (exception) {
JVMCI::release_handle(handle); _runtime->release_handle(handle);
return JVMCIObject(); return JVMCIObject();
} }
assert(asMethod(method_object) == method(), "must be"); assert(asMethod(method_object) == method(), "must be");
if (get_HotSpotResolvedJavaMethodImpl_metadataHandle(method_object) != (jlong) handle) { if (get_HotSpotResolvedJavaMethodImpl_metadataHandle(method_object) != (jlong) handle) {
JVMCI::release_handle(handle); _runtime->release_handle(handle);
} }
assert(!method_object.is_null(), "must be"); assert(!method_object.is_null(), "must be");
return method_object; return method_object;
@ -1137,7 +1063,7 @@ JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS)
type = wrap((oop)result.get_jobject()); type = wrap((oop)result.get_jobject());
} }
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
HandleMark hm(THREAD); HandleMark hm(THREAD);
type = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedObjectTypeImpl::clazz(), 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 JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMCI_TRAPS) {
JVMCIObject cp_object; JVMCIObject cp_object;
jmetadata handle = JVMCI::allocate_handle(cp); jmetadata handle = _runtime->allocate_handle(cp);
jboolean exception = false; jboolean exception = false;
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
JavaValue result(T_OBJECT); JavaValue result(T_OBJECT);
JavaCallArguments args; JavaCallArguments args;
args.push_long((jlong) handle); 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()); cp_object = wrap((oop)result.get_jobject());
} }
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
cp_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotConstantPool::clazz(), cp_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotConstantPool::clazz(),
JNIJVMCI::HotSpotConstantPool_fromMetaspace_method(), JNIJVMCI::HotSpotConstantPool_fromMetaspace_method(),
(jlong) handle)); (jlong) handle));
@ -1180,7 +1106,7 @@ JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMC
} }
if (exception) { if (exception) {
JVMCI::release_handle(handle); _runtime->release_handle(handle);
return JVMCIObject(); return JVMCIObject();
} }
@ -1191,69 +1117,69 @@ JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMC
} }
JVMCIPrimitiveArray JVMCIEnv::new_booleanArray(int length, JVMCI_TRAPS) { JVMCIPrimitiveArray JVMCIEnv::new_booleanArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_boolArray(length, CHECK_(JVMCIObject())); typeArrayOop result = oopFactory::new_boolArray(length, CHECK_(JVMCIObject()));
return wrap(result); return wrap(result);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jbooleanArray result = jni()->NewBooleanArray(length); jbooleanArray result = jni()->NewBooleanArray(length);
return wrap(result); return wrap(result);
} }
} }
JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) { JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_byteArray(length, CHECK_(JVMCIObject())); typeArrayOop result = oopFactory::new_byteArray(length, CHECK_(JVMCIObject()));
return wrap(result); return wrap(result);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jbyteArray result = jni()->NewByteArray(length); jbyteArray result = jni()->NewByteArray(length);
return wrap(result); return wrap(result);
} }
} }
JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) { JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj ())->array_klass(CHECK_(JVMCIObject())); Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj ())->array_klass(CHECK_(JVMCIObject()));
objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject())); objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject()));
return wrap(result); return wrap(result);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::byte_array(), NULL); jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::byte_array(), NULL);
return wrap(result); return wrap(result);
} }
} }
JVMCIPrimitiveArray JVMCIEnv::new_intArray(int length, JVMCI_TRAPS) { JVMCIPrimitiveArray JVMCIEnv::new_intArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_intArray(length, CHECK_(JVMCIObject())); typeArrayOop result = oopFactory::new_intArray(length, CHECK_(JVMCIObject()));
return wrap(result); return wrap(result);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jintArray result = jni()->NewIntArray(length); jintArray result = jni()->NewIntArray(length);
return wrap(result); return wrap(result);
} }
} }
JVMCIPrimitiveArray JVMCIEnv::new_longArray(int length, JVMCI_TRAPS) { JVMCIPrimitiveArray JVMCIEnv::new_longArray(int length, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
typeArrayOop result = oopFactory::new_longArray(length, CHECK_(JVMCIObject())); typeArrayOop result = oopFactory::new_longArray(length, CHECK_(JVMCIObject()));
return wrap(result); return wrap(result);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jlongArray result = jni()->NewLongArray(length); jlongArray result = jni()->NewLongArray(length);
return wrap(result); return wrap(result);
} }
} }
JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS) { JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
HotSpotJVMCI::VMField::klass()->initialize(CHECK_(JVMCIObject())); HotSpotJVMCI::VMField::klass()->initialize(CHECK_(JVMCIObject()));
oop obj = HotSpotJVMCI::VMField::klass()->allocate_instance(CHECK_(JVMCIObject())); oop obj = HotSpotJVMCI::VMField::klass()->allocate_instance(CHECK_(JVMCIObject()));
HotSpotJVMCI::VMField::set_name(this, obj, HotSpotJVMCI::resolve(name)); 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)); HotSpotJVMCI::VMField::set_value(this, obj, HotSpotJVMCI::resolve(value));
return wrap(obj); return wrap(obj);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::VMField::clazz(), jobject result = jni()->NewObject(JNIJVMCI::VMField::clazz(),
JNIJVMCI::VMField::constructor(), JNIJVMCI::VMField::constructor(),
get_jobject(name), get_jobject(type), offset, address, get_jobject(value)); 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) { JVMCIObject JVMCIEnv::new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject value, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
HotSpotJVMCI::VMFlag::klass()->initialize(CHECK_(JVMCIObject())); HotSpotJVMCI::VMFlag::klass()->initialize(CHECK_(JVMCIObject()));
oop obj = HotSpotJVMCI::VMFlag::klass()->allocate_instance(CHECK_(JVMCIObject())); oop obj = HotSpotJVMCI::VMFlag::klass()->allocate_instance(CHECK_(JVMCIObject()));
HotSpotJVMCI::VMFlag::set_name(this, obj, HotSpotJVMCI::resolve(name)); 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)); HotSpotJVMCI::VMFlag::set_value(this, obj, HotSpotJVMCI::resolve(value));
return wrap(obj); return wrap(obj);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::VMFlag::clazz(), jobject result = jni()->NewObject(JNIJVMCI::VMFlag::clazz(),
JNIJVMCI::VMFlag::constructor(), JNIJVMCI::VMFlag::constructor(),
get_jobject(name), get_jobject(type), get_jobject(value)); 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) { JVMCIObject JVMCIEnv::new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
HotSpotJVMCI::VMIntrinsicMethod::klass()->initialize(CHECK_(JVMCIObject())); HotSpotJVMCI::VMIntrinsicMethod::klass()->initialize(CHECK_(JVMCIObject()));
oop obj = HotSpotJVMCI::VMIntrinsicMethod::klass()->allocate_instance(CHECK_(JVMCIObject())); oop obj = HotSpotJVMCI::VMIntrinsicMethod::klass()->allocate_instance(CHECK_(JVMCIObject()));
HotSpotJVMCI::VMIntrinsicMethod::set_declaringClass(this, obj, HotSpotJVMCI::resolve(declaringClass)); 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); HotSpotJVMCI::VMIntrinsicMethod::set_id(this, obj, id);
return wrap(obj); return wrap(obj);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::VMIntrinsicMethod::clazz(), jobject result = jni()->NewObject(JNIJVMCI::VMIntrinsicMethod::clazz(),
JNIJVMCI::VMIntrinsicMethod::constructor(), JNIJVMCI::VMIntrinsicMethod::constructor(),
get_jobject(declaringClass), get_jobject(name), get_jobject(descriptor), id); 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); return wrap(constant);
} else { } else {
jlong handle = make_handle(obj); jlong handle = make_handle(obj);
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
jobject result = jni()->NewObject(JNIJVMCI::IndirectHotSpotObjectConstantImpl::clazz(), jobject result = jni()->NewObject(JNIJVMCI::IndirectHotSpotObjectConstantImpl::clazz(),
JNIJVMCI::IndirectHotSpotObjectConstantImpl::constructor(), JNIJVMCI::IndirectHotSpotObjectConstantImpl::constructor(),
handle, compressed, dont_register); handle, compressed, dont_register);
@ -1385,7 +1311,7 @@ JVMCIObject JVMCIEnv::wrap(jobject object) {
jlong JVMCIEnv::make_handle(const Handle& obj) { jlong JVMCIEnv::make_handle(const Handle& obj) {
assert(!obj.is_null(), "should only create handle for non-NULL oops"); 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; return (jlong) handle;
} }
@ -1399,15 +1325,15 @@ oop JVMCIEnv::resolve_handle(jlong objectHandle) {
} }
JVMCIObject JVMCIEnv::create_string(const char* str, JVMCI_TRAPS) { JVMCIObject JVMCIEnv::create_string(const char* str, JVMCI_TRAPS) {
if (is_hotspot()) {
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
if (is_hotspot()) {
Handle result = java_lang_String::create_from_str(str, CHECK_(JVMCIObject())); Handle result = java_lang_String::create_from_str(str, CHECK_(JVMCIObject()));
return HotSpotJVMCI::wrap(result()); return HotSpotJVMCI::wrap(result());
} else { } else {
jobject result; jobject result;
jboolean exception = false; jboolean exception = false;
{ {
JNIAccessMark jni(this); JNIAccessMark jni(this, THREAD);
result = jni()->NewStringUTF(str); result = jni()->NewStringUTF(str);
exception = jni()->ExceptionCheck(); exception = jni()->ExceptionCheck();
} }

View file

@ -44,8 +44,11 @@ class JVMCIRuntime;
#define JVMCI_EXCEPTION_CHECK(env, ...) \ #define JVMCI_EXCEPTION_CHECK(env, ...) \
do { \ do { \
if (env->ExceptionCheck()) { \ if (env->ExceptionCheck()) { \
if (env != JavaThread::current()->jni_environment() && JVMCIEnv::get_shared_library_path() != NULL) { \ if (env != JavaThread::current()->jni_environment()) { \
tty->print_cr("In JVMCI shared library (%s):", JVMCIEnv::get_shared_library_path()); \ 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__); \ tty->print_cr(__VA_ARGS__); \
return; \ return; \
@ -143,16 +146,6 @@ class JVMCICompileState : public ResourceObj {
class JVMCIEnv : public ResourceObj { class JVMCIEnv : public ResourceObj {
friend class JNIAccessMark; 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. // Initializes the _env, _mode and _runtime fields.
void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env); void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env);
@ -384,10 +377,8 @@ public:
// These are analagous to the JNI routines // These are analagous to the JNI routines
JVMCIObject make_local(JVMCIObject object); JVMCIObject make_local(JVMCIObject object);
JVMCIObject make_global(JVMCIObject object); JVMCIObject make_global(JVMCIObject object);
JVMCIObject make_weak(JVMCIObject object);
void destroy_local(JVMCIObject object); void destroy_local(JVMCIObject object);
void destroy_global(JVMCIObject object); void destroy_global(JVMCIObject object);
void destroy_weak(JVMCIObject object);
// Deoptimizes the nmethod (if any) in the HotSpotNmethod.address // Deoptimizes the nmethod (if any) in the HotSpotNmethod.address
// field of mirror. The field is subsequently zeroed. // field of mirror. The field is subsequently zeroed.
@ -399,9 +390,6 @@ public:
JVMCICompileState* _compile_state; JVMCICompileState* _compile_state;
public: 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 // Determines if this is for the JVMCI runtime in the HotSpot
// heap (true) or the shared library heap (false). // 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. // accessor itself does not include a class initialization check.
ik->initialize(CHECK); ik->initialize(CHECK);
} }
TRACE_jvmci_2(" field offset for %s %s.%s = %d", signature, ik->external_name(), name, dest_offset);
} }
#ifndef PRODUCT #ifndef PRODUCT
@ -118,6 +119,7 @@ jmethodID JNIJVMCI::_HotSpotResolvedPrimitiveType_fromMetaspace_method;
#define START_CLASS(className, fullClassName) { \ #define START_CLASS(className, fullClassName) { \
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::fullClassName(), true, CHECK); \ Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::fullClassName(), true, CHECK); \
className::_klass = InstanceKlass::cast(k); \ className::_klass = InstanceKlass::cast(k); \
TRACE_jvmci_2(" klass for %s = " PTR_FORMAT, k->external_name(), p2i(k)); \
className::_klass->initialize(CHECK); className::_klass->initialize(CHECK);
#define END_CLASS } #define END_CLASS }
@ -286,6 +288,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
return; return;
} }
jfieldID current = fieldid;
if (static_field) { if (static_field) {
// Class initialization barrier // Class initialization barrier
fieldid = env->GetStaticFieldID(clazz, name, signature); fieldid = env->GetStaticFieldID(clazz, name, signature);
@ -293,6 +296,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
// Class initialization barrier // Class initialization barrier
fieldid = env->GetFieldID(clazz, name, signature); 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()) { if (env->ExceptionCheck()) {
env->ExceptionDescribe(); env->ExceptionDescribe();
@ -312,7 +316,9 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
jclass k = env->FindClass(current_class_name); \ jclass k = env->FindClass(current_class_name); \
JVMCI_EXCEPTION_CHECK(env, "FindClass(%s)", current_class_name); \ JVMCI_EXCEPTION_CHECK(env, "FindClass(%s)", current_class_name); \
assert(k != NULL, #fullClassName " not initialized"); \ 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; } #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(); \ fileStream* st = JVMCIGlobals::get_jni_config_file(); \
st->print_cr("method %s %s %s", current_class_name, methodName, signature); \ st->print_cr("method %s %s %s", current_class_name, methodName, signature); \
} else { \ } else { \
jmethodID current = dst; \
dst = env->jniGetMethod(clazz, methodName, signature); \ 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"); \ 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) \ #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 CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(f)) #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()) { if (env != JavaThread::current()->jni_environment()) {
jclass clazz = env->FindClass("jdk/vm/ci/hotspot/CompilerToVM"); JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) }};
if (env->ExceptionCheck()) { JNINativeMethod JVMCI_nmethods[] = {{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }};
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 JVMCI_native_methods[] = { register_natives_for_class(env, NULL, "jdk/vm/ci/hotspot/CompilerToVM", CompilerToVM_nmethods, 1);
{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }, register_natives_for_class(env, JVMCI::clazz(), "jdk/vm/ci/runtime/JVMCI", JVMCI_nmethods, 1);
};
env->RegisterNatives(JVMCI::clazz(), JVMCI_native_methods, 1);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
guarantee(false, "");
}
} }
} }

View file

@ -639,6 +639,7 @@ class JNIJVMCI {
static void initialize_ids(JNIEnv* env); 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 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 jobject resolve_handle(JVMCIObject obj) { return obj.as_jobject(); }
static JVMCIObject wrap(jobject obj) { return JVMCIObject(obj, false); } static JVMCIObject wrap(jobject obj) { return JVMCIObject(obj, false); }

View file

@ -25,9 +25,12 @@
#include "classfile/javaClasses.inline.hpp" #include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp" #include "classfile/symbolTable.hpp"
#include "compiler/compileBroker.hpp" #include "compiler/compileBroker.hpp"
#include "gc/shared/oopStorage.inline.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "jvmci/jniAccessMark.inline.hpp" #include "jvmci/jniAccessMark.inline.hpp"
#include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/jvmciCompilerToVM.hpp"
#include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciRuntime.hpp"
#include "jvmci/metadataHandles.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "memory/oopFactory.hpp" #include "memory/oopFactory.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
@ -35,11 +38,13 @@
#include "oops/method.inline.hpp" #include "oops/method.inline.hpp"
#include "oops/objArrayKlass.hpp" #include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp" #include "runtime/biasedLocking.hpp"
#include "runtime/deoptimization.hpp" #include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp" #include "runtime/frame.inline.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
#if INCLUDE_G1GC #if INCLUDE_G1GC
#include "gc/g1/g1ThreadLocalData.hpp" #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) { void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
if (is_HotSpotJVMCIRuntime_initialized()) { if (is_HotSpotJVMCIRuntime_initialized()) {
if (JVMCIENV->is_hotspot() && UseJVMCINativeLibrary) { if (JVMCIENV->is_hotspot() && UseJVMCINativeLibrary) {
@ -718,29 +873,32 @@ void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
JVMCIObject result = JVMCIENV->call_HotSpotJVMCIRuntime_runtime(JVMCI_CHECK); JVMCIObject result = JVMCIENV->call_HotSpotJVMCIRuntime_runtime(JVMCI_CHECK);
_HotSpotJVMCIRuntime_instance = JVMCIENV->make_global(result); _HotSpotJVMCIRuntime_instance = JVMCIENV->make_global(result);
JVMCI::_is_initialized = true;
} }
void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) { void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
assert(this != NULL, "sanity");
// Check first without JVMCI_lock // Check first without JVMCI_lock
if (_initialized) { if (_init_state == fully_initialized) {
return; return;
} }
MutexLocker locker(JVMCI_lock); MutexLocker locker(JVMCI_lock);
// Check again under JVMCI_lock // Check again under JVMCI_lock
if (_initialized) { if (_init_state == fully_initialized) {
return; return;
} }
while (_being_initialized) { while (_init_state == being_initialized) {
TRACE_jvmci_1("waiting for initialization of JVMCI runtime %d", _id);
JVMCI_lock->wait(); JVMCI_lock->wait();
if (_initialized) { if (_init_state == fully_initialized) {
TRACE_jvmci_1("done waiting for initialization of JVMCI runtime %d", _id);
return; return;
} }
} }
_being_initialized = true; TRACE_jvmci_1("initializing JVMCI runtime %d", _id);
_init_state = being_initialized;
{ {
MutexUnlocker unlock(JVMCI_lock); MutexUnlocker unlock(JVMCI_lock);
@ -759,6 +917,11 @@ void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
fatal("JNI exception during init"); 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_BOOLEAN, JVMCI_CHECK_EXIT_((void)0));
create_jvmci_primitive_type(T_BYTE, 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)); create_jvmci_primitive_type(T_CHAR, JVMCI_CHECK_EXIT_((void)0));
@ -774,8 +937,8 @@ void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
} }
} }
_initialized = true; _init_state = fully_initialized;
_being_initialized = false; TRACE_jvmci_1("initialized JVMCI runtime %d", _id);
JVMCI_lock->notify_all(); JVMCI_lock->notify_all();
} }
@ -817,8 +980,7 @@ JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
return _HotSpotJVMCIRuntime_instance; return _HotSpotJVMCIRuntime_instance;
} }
// private static void CompilerToVM.registerNatives()
// private void CompilerToVM.registerNatives()
JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass))
JNI_JVMCIENV(thread, env); JNI_JVMCIENV(thread, env);
@ -854,16 +1016,17 @@ JVM_END
void JVMCIRuntime::shutdown() { void JVMCIRuntime::shutdown() {
if (is_HotSpotJVMCIRuntime_initialized()) { if (_HotSpotJVMCIRuntime_instance.is_non_null()) {
_shutdown_called = true; TRACE_jvmci_1("shutting down HotSpotJVMCIRuntime for JVMCI runtime %d", _id);
JVMCIEnv __stack_jvmci_env__(JavaThread::current(), _HotSpotJVMCIRuntime_instance.is_hotspot(), __FILE__, __LINE__);
THREAD_JVMCIENV(JavaThread::current()); JVMCIEnv* JVMCIENV = &__stack_jvmci_env__;
JVMCIENV->call_HotSpotJVMCIRuntime_shutdown(_HotSpotJVMCIRuntime_instance); JVMCIENV->call_HotSpotJVMCIRuntime_shutdown(_HotSpotJVMCIRuntime_instance);
TRACE_jvmci_1("shut down HotSpotJVMCIRuntime for JVMCI runtime %d", _id);
} }
} }
void JVMCIRuntime::bootstrap_finished(TRAPS) { void JVMCIRuntime::bootstrap_finished(TRAPS) {
if (is_HotSpotJVMCIRuntime_initialized()) { if (_HotSpotJVMCIRuntime_instance.is_non_null()) {
THREAD_JVMCIENV(JavaThread::current()); THREAD_JVMCIENV(JavaThread::current());
JVMCIENV->call_HotSpotJVMCIRuntime_bootstrapFinished(_HotSpotJVMCIRuntime_instance, JVMCIENV); 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) { if (compiler->is_bootstrapping() && is_osr) {
// no OSR compilations during bootstrap - the compiler is just too slow at this point, // no OSR compilations during bootstrap - the compiler is just too slow at this point,
// and we know that there are no endless loops // 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; return;
} }
if (JVMCI::shutdown_called()) { if (JVMCI::in_shutdown()) {
compile_state->set_failure(false, "Avoiding compilation during shutdown"); compile_state->set_failure(false, "Avoiding compilation during shutdown");
return; return;
} }
@ -1521,3 +1684,14 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
return result; 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/jvmci.hpp"
#include "jvmci/jvmciExceptions.hpp" #include "jvmci/jvmciExceptions.hpp"
#include "jvmci/jvmciObject.hpp" #include "jvmci/jvmciObject.hpp"
#include "utilities/linkedlist.hpp"
class JVMCIEnv; class JVMCIEnv;
class JVMCICompiler; class JVMCICompiler;
class JVMCICompileState; class JVMCICompileState;
class MetadataHandles;
// Encapsulates the JVMCI metadata for an nmethod. // Encapsulates the JVMCI metadata for an nmethod.
// JVMCINMethodData objects are inlined into nmethods // JVMCINMethodData objects are inlined into nmethods
@ -86,6 +88,7 @@ public:
// A top level class that represents an initialized JVMCI runtime. // A top level class that represents an initialized JVMCI runtime.
// There is one instance of this class per HotSpotJVMCIRuntime object. // There is one instance of this class per HotSpotJVMCIRuntime object.
class JVMCIRuntime: public CHeapObj<mtJVMCI> { class JVMCIRuntime: public CHeapObj<mtJVMCI> {
friend class JVMCI;
public: public:
// Constants describing whether JVMCI wants to be able to adjust the compilation // 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 // 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: 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; 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); JVMCIObject create_jvmci_primitive_type(BasicType type, JVMCI_TRAPS);
@ -131,44 +150,74 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
constantTag tag); constantTag tag);
public: public:
JVMCIRuntime() { JVMCIRuntime(int id);
_initialized = false;
_being_initialized = false;
_shutdown_called = false;
}
/** int id() const { return _id; }
* Compute offsets and construct any state required before executing JVMCI code.
*/ // 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); void initialize(JVMCIEnv* jvmciEnv);
/** // Allocation and management of JNI global object handles.
* Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary 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); JVMCIObject get_HotSpotJVMCIRuntime(JVMCI_TRAPS);
bool is_HotSpotJVMCIRuntime_initialized() { bool is_HotSpotJVMCIRuntime_initialized() {
return _HotSpotJVMCIRuntime_instance.is_non_null(); return _HotSpotJVMCIRuntime_instance.is_non_null();
} }
/** // Gets the current HotSpotJVMCIRuntime instance for this runtime which
* Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime() // may be a "null" JVMCIObject value.
*/ JVMCIObject probe_HotSpotJVMCIRuntime() {
return _HotSpotJVMCIRuntime_instance;
}
// Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime()
void initialize_JVMCI(JVMCI_TRAPS); void initialize_JVMCI(JVMCI_TRAPS);
/** // Explicitly initialize HotSpotJVMCIRuntime itself
* Explicitly initialize HotSpotJVMCIRuntime itself
*/
void initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS); void initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS);
void call_getCompiler(TRAPS); void call_getCompiler(TRAPS);
// Shuts down this runtime by calling HotSpotJVMCIRuntime.shutdown().
void shutdown(); void shutdown();
bool shutdown_called() {
return _shutdown_called;
}
void bootstrap_finished(TRAPS); void bootstrap_finished(TRAPS);
// Look up a klass by name from a particular class loader (the accessor's). // 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, char* speculations,
int speculations_len); 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 exit_on_pending_exception(JVMCIEnv* JVMCIENV, const char* message);
static void describe_pending_hotspot_exception(JavaThread* THREAD, bool clear); static void describe_pending_hotspot_exception(JavaThread* THREAD, bool clear);
@ -339,6 +386,11 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
// Test only function // Test only function
static jint test_deoptimize_call_int(JavaThread* thread, int value); 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. // Tracing macros.
@ -349,10 +401,11 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
#define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else #define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else
#define IF_TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5)) ; 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_(n) if (!(JVMCITraceLevel >= n && JVMCIRuntime::trace_prefix(n))) ; 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_1 TRACE_jvmci_(1)
#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(PTR_FORMAT " JVMCITrace-3: ", p2i(JavaThread::current())), true))) ; else tty->print_cr #define TRACE_jvmci_2 TRACE_jvmci_(2)
#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(PTR_FORMAT " JVMCITrace-4: ", p2i(JavaThread::current())), true))) ; else tty->print_cr #define TRACE_jvmci_3 TRACE_jvmci_(3)
#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(PTR_FORMAT " JVMCITrace-5: ", p2i(JavaThread::current())), true))) ; else tty->print_cr #define TRACE_jvmci_4 TRACE_jvmci_(4)
#define TRACE_jvmci_5 TRACE_jvmci_(5)
#endif // SHARE_JVMCI_JVMCIRUNTIME_HPP #endif // SHARE_JVMCI_JVMCIRUNTIME_HPP

View file

@ -22,19 +22,17 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "jvmci/metadataHandleBlock.hpp" #include "jvmci/metadataHandles.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
MetadataHandleBlock* MetadataHandleBlock::_last = NULL; jmetadata MetadataHandles::allocate_metadata_handle(Metadata* obj) {
intptr_t MetadataHandleBlock::_free_list = 0;
int MetadataHandleBlock::_allocate_before_rebuild = 0;
jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) {
assert(obj->is_valid() && obj->is_metadata(), "must be"); assert(obj->is_valid() && obj->is_metadata(), "must be");
if (_last == NULL) { if (_head == NULL) {
// This is the first allocation. // This is the first allocation.
_last = this; _head = new MetadataHandleBlock();
_last = _head;
_num_blocks++;
} }
HandleRecord* handle = get_handle(); HandleRecord* handle = get_handle();
@ -47,7 +45,7 @@ jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) {
return (jmetadata) handle; return (jmetadata) handle;
} }
// Check if unused block follow last // Check if an unused block follows last
if (_last->_next != NULL) { if (_last->_next != NULL) {
// update last and retry // update last and retry
_last = _last->_next; _last = _last->_next;
@ -59,20 +57,20 @@ jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) {
rebuild_free_list(); // updates _allocate_before_rebuild counter rebuild_free_list(); // updates _allocate_before_rebuild counter
} else { } else {
// Append new block // Append new block
// This can block, but the caller has a metadata handle around this object. _last->_next = new MetadataHandleBlock();
_last->_next = allocate_block();
_last = _last->_next; _last = _last->_next;
_allocate_before_rebuild--; _allocate_before_rebuild--;
_num_blocks++;
} }
return allocate_metadata_handle(obj); // retry 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"); assert(_allocate_before_rebuild == 0 && _free_list == 0, "just checking");
int free = 0; int free = 0;
int blocks = 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++) { for (int index = 0; index < current->_top; index++) {
HandleRecord* handle = &(current->_handles)[index]; HandleRecord* handle = &(current->_handles)[index];
if (handle->value() == NULL) { 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 // 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++; 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 // 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 // as well, otherwise we append a corresponding number of new blocks before
// attempting a free list rebuild again. // 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; int extra = total - 2*free;
if (extra > 0) { if (extra > 0) {
// Not as many free handles as we would like - compute number of new blocks to append // 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*)) { void MetadataHandles::clear() {
for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) { _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++) { for (int index = 0; index < current->_top; index++) {
HandleRecord* root = &(current->_handles)[index]; HandleRecord* root = &(current->_handles)[index];
Metadata* value = root->value(); Metadata* value = root->value();
// traverse heap pointers only, not deleted handles or free list // traverse heap pointers only, not deleted handles or free list
// pointers // pointers
if (value != NULL && ((intptr_t) value & ptr_tag) == 0) { 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); f(value);
} }
} }
// the next handle block is valid only if current block is full // 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; 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 // 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. // weak references they will be cleared at some point in the future when the reference cleaning logic is run.
void MetadataHandleBlock::do_unloading() { void MetadataHandles::do_unloading() {
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++) { for (int index = 0; index < current->_top; index++) {
HandleRecord* handle = &(current->_handles)[index]; HandleRecord* handle = &(current->_handles)[index];
Metadata* value = handle->value(); Metadata* value = handle->value();
@ -152,7 +164,7 @@ void MetadataHandleBlock::do_unloading() {
} }
} }
// the next handle block is valid only if current block is full // 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; break;
} }
} }

View file

@ -21,8 +21,8 @@
* questions. * questions.
*/ */
#ifndef SHARE_JVMCI_METADATAHANDLEBLOCK_HPP #ifndef SHARE_JVMCI_METADATAHANDLES_HPP
#define SHARE_JVMCI_METADATAHANDLEBLOCK_HPP #define SHARE_JVMCI_METADATAHANDLES_HPP
#include "oops/constantPool.hpp" #include "oops/constantPool.hpp"
#include "oops/metadata.hpp" #include "oops/metadata.hpp"
@ -72,22 +72,15 @@ struct _jmetadata {
typedef struct _jmetadata HandleRecord; typedef struct _jmetadata HandleRecord;
typedef struct _jmetadata *jmetadata; 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> { class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
friend class MetadataHandles;
private: private:
enum SomeConstants { enum SomeConstants {
block_size_in_handles = 32, // Number of handles per handle block block_size_in_handles = 32 // Number of handles per handle block
ptr_tag = 1,
ptr_mask = ~((intptr_t)ptr_tag)
}; };
// Free handles always have their low bit set so those pointers can // Free handles always have their low bit set so those pointers can
// be distinguished from handles which are in use. The last handle // 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 // 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 int _top; // Index of next unused handle
MetadataHandleBlock* _next; // Link to next block 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() { MetadataHandleBlock() {
_top = 0; _top = 0;
_next = NULL; _next = NULL;
@ -121,20 +108,42 @@ class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
return "<missing>"; return "<missing>";
#endif #endif
} }
};
static HandleRecord* get_free_handle() { // JVMCI maintains direct references to metadata. To make these references safe in the face of
assert(_free_list != 0, "should check before calling"); // 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); HandleRecord* handle = (HandleRecord*) (_free_list & ptr_mask);
_free_list = (ptr_mask & (intptr_t) (handle->value())); _free_list = (ptr_mask & (intptr_t) (handle->value()));
assert(_free_list != ptr_tag, "should be null"); assert(_free_list != ptr_tag, "should be null");
handle->set_value(NULL); _num_free_handles--;
return handle; return handle;
} }
static HandleRecord* get_handle() { HandleRecord* get_handle() {
assert(_last != NULL, "sanity"); assert(_last != NULL, "sanity");
// Try last block // 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++]; return &(_last->_handles)[_last->_top++];
} else if (_free_list != 0) { } else if (_free_list != 0) {
// Try free list // Try free list
@ -148,23 +157,39 @@ class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
jmetadata allocate_metadata_handle(Metadata* metadata); jmetadata allocate_metadata_handle(Metadata* metadata);
public: 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 methodHandle& handle) { return allocate_metadata_handle(handle()); }
jmetadata allocate_handle(const constantPoolHandle& 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
void chain_free_list(HandleRecord* handle) {
// Adds `handle` to the free list in this block
static void chain_free_list(HandleRecord* handle) {
handle->set_value((Metadata*) (ptr_tag | _free_list)); handle->set_value((Metadata*) (ptr_tag | _free_list));
#ifdef METADATA_TRACK_NAMES #ifdef METADATA_TRACK_NAMES
handle->set_name(NULL); handle->set_name(NULL);
#endif #endif
_free_list = (intptr_t) handle; _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 metadata_do(void f(Metadata*));
void do_unloading(); 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); CompilerToVM.compilerToVM().deleteGlobalHandle(handle);
} else { } else {
// Setting the target of a jmetadata handle to 0 enables // Setting the target of a jmetadata handle to 0 enables
// the handle to be reused. See MetadataHandleBlock in // the handle to be reused. See MetadataHandles in
// jvmciRuntime.cpp for more info. // metadataHandles.hpp for more info.
long value = UNSAFE.getLong(null, handle); long value = UNSAFE.getLong(null, handle);
UNSAFE.compareAndSetLong(null, handle, value, 0); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Formatter;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -210,6 +211,15 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
return o.toString(); 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. * A list of all supported JVMCI options.
*/ */
@ -245,7 +255,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
private final Class<?> type; private final Class<?> type;
@NativeImageReinitialize private Object value; @NativeImageReinitialize private Object value;
private final Object defaultValue; private final Object defaultValue;
private boolean isDefault; private boolean isDefault = true;
private final String[] helpLines; private final String[] helpLines;
Option(Class<?> type, Object defaultValue, String... helpLines) { Option(Class<?> type, Object defaultValue, String... helpLines) {
@ -253,12 +263,13 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
this.type = type; this.type = type;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
this.helpLines = helpLines; 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") @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
private Object getValue() { private void init(String propertyValue) {
if (value == null) { assert value == null : "cannot re-initialize " + name();
String propertyValue = Services.getSavedProperty(getPropertyName());
if (propertyValue == null) { if (propertyValue == null) {
this.value = defaultValue == null ? NULL_VALUE : defaultValue; this.value = defaultValue == null ? NULL_VALUE : defaultValue;
this.isDefault = true; this.isDefault = true;
@ -273,7 +284,16 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
this.isDefault = false; 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) { private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
@ -454,6 +529,9 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
System.setErr(vmLogStream); System.setErr(vmLogStream);
} }
// Initialize the Option values.
Option.parse();
String hostArchitecture = config.getHostArchitectureName(); String hostArchitecture = config.getHostArchitectureName();
HotSpotJVMCIBackendFactory factory; HotSpotJVMCIBackendFactory factory;
@ -712,11 +790,18 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
return hsResult; return hsResult;
} }
/**
* Guard to ensure shut down actions are performed at most once.
*/
private boolean isShutdown;
/** /**
* Shuts down the runtime. * Shuts down the runtime.
*/ */
@VMEntryPoint @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 // Cleaners are normally only processed when a new Cleaner is
// instantiated so process all remaining cleaners now. // instantiated so process all remaining cleaners now.
Cleaner.clean(); Cleaner.clean();
@ -725,6 +810,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
vmEventListener.notifyShutdown(); vmEventListener.notifyShutdown();
} }
} }
}
/** /**
* Notify on completion of a bootstrap. * Notify on completion of a bootstrap.
@ -914,8 +1000,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
* </pre> * </pre>
* *
* The implementation of the native {@code JCompile.compile0} method would be in the JVMCI * 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} * shared library that contains the JVMCI compiler. The {@code JCompile.compile0} implementation
* implementation will be exported as the following JNI-compatible symbol: * must be exported as the following JNI-compatible symbol:
* *
* <pre> * <pre>
* Java_com_jcompile_JCompile_compile0 * 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" * @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 * @return info about the Java VM in the JVMCI shared library {@code JavaVM*}. The info is
* the Java VM in the JVMCI shared library, and the remaining values are the first 3 * encoded in a long array as follows:
* pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) *
* <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 NullPointerException if {@code clazz == null}
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary}) * {@code -XX:-UseJVMCINativeLibrary})
@ -1017,6 +1112,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
* {@code -XX:-UseJVMCINativeLibrary}) * {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the peer runtime has not been initialized or there is an * @throws IllegalStateException if the peer runtime has not been initialized or there is an
* error while trying to attach the thread * 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) { public boolean attachCurrentThread(boolean asDaemon) {
return compilerToVm.attachCurrentThread(asDaemon); return compilerToVm.attachCurrentThread(asDaemon);