8223332: Update JVMCI

Reviewed-by: never, dnsimon
This commit is contained in:
Vladimir Kozlov 2019-05-06 20:05:19 -07:00
parent 29a4ad9a87
commit 72f082e925
30 changed files with 1038 additions and 345 deletions

View file

@ -70,7 +70,6 @@
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
#include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciEnv.hpp"
#include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciRuntime.hpp"
#include "runtime/vframe.hpp"
#endif #endif
#ifdef COMPILER2 #ifdef COMPILER2
#include "opto/c2compiler.hpp" #include "opto/c2compiler.hpp"
@ -1063,20 +1062,22 @@ void CompileBroker::compile_method_base(const methodHandle& method,
} }
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
if (UseJVMCICompiler && blocking && !UseJVMCINativeLibrary) { if (UseJVMCICompiler && blocking) {
// Don't allow blocking compiles for requests triggered by JVMCI. // Don't allow blocking compiles for requests triggered by JVMCI.
if (thread->is_Compiler_thread()) { if (thread->is_Compiler_thread()) {
blocking = false; blocking = false;
} }
// Don't allow blocking compiles if inside a class initializer or while performing class loading if (!UseJVMCINativeLibrary) {
vframeStream vfst((JavaThread*) thread); // Don't allow blocking compiles if inside a class initializer or while performing class loading
for (; !vfst.at_end(); vfst.next()) { vframeStream vfst((JavaThread*) thread);
if (vfst.method()->is_static_initializer() || for (; !vfst.at_end(); vfst.next()) {
(vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && if (vfst.method()->is_static_initializer() ||
vfst.method()->name() == vmSymbols::loadClass_name())) { (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
blocking = false; vfst.method()->name() == vmSymbols::loadClass_name())) {
break; blocking = false;
break;
}
} }
} }
@ -2063,7 +2064,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
compilable = ciEnv::MethodCompilable_never; compilable = ciEnv::MethodCompilable_never;
} else { } else {
JVMCICompileState compile_state(task, system_dictionary_modification_counter); JVMCICompileState compile_state(task, system_dictionary_modification_counter);
JVMCIEnv env(&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); env.runtime()->compile_method(&env, jvmci, method, osr_bci);

File diff suppressed because it is too large Load diff

View file

@ -160,13 +160,14 @@ class JavaArgumentUnboxer : public SignatureIterator {
}; };
class JNIHandleMark : public StackObj { class JNIHandleMark : public StackObj {
JavaThread* _thread;
public: public:
JNIHandleMark() { push_jni_handle_block(); } JNIHandleMark(JavaThread* thread) : _thread(thread) { push_jni_handle_block(thread); }
~JNIHandleMark() { pop_jni_handle_block(); } ~JNIHandleMark() { pop_jni_handle_block(_thread); }
private: private:
static void push_jni_handle_block(); static void push_jni_handle_block(JavaThread* thread);
static void pop_jni_handle_block(); static void pop_jni_handle_block(JavaThread* thread);
}; };
#endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP #endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP

View file

@ -129,11 +129,10 @@ void JVMCIEnv::copy_saved_properties() {
} }
} }
JNIEnv* JVMCIEnv::attach_shared_library() { JNIEnv* JVMCIEnv::init_shared_library(JavaThread* thread) {
if (_shared_library_javavm == NULL) { if (_shared_library_javavm == NULL) {
MutexLocker locker(JVMCI_lock); MutexLocker locker(JVMCI_lock);
if (_shared_library_javavm == NULL) { if (_shared_library_javavm == NULL) {
char path[JVM_MAXPATHLEN]; char path[JVM_MAXPATHLEN];
char ebuf[1024]; char ebuf[1024];
if (JVMCILibPath != NULL) { if (JVMCILibPath != NULL) {
@ -179,85 +178,107 @@ JNIEnv* JVMCIEnv::attach_shared_library() {
} }
} }
} }
JNIEnv* env;
if (_shared_library_javavm->AttachCurrentThread((void**)&env, NULL) == JNI_OK) {
guarantee(env != NULL, "missing env");
return env;
}
fatal("Error attaching current thread to JVMCI shared library JNI interface");
return NULL; return NULL;
} }
void JVMCIEnv::init_env_mode_runtime(JNIEnv* parent_env) { void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
assert(thread != NULL, "npe");
// By default there is only one runtime which is the compiler runtime. // By default there is only one runtime which is the compiler runtime.
_runtime = JVMCI::compiler_runtime(); _runtime = JVMCI::compiler_runtime();
_env = NULL;
_pop_frame_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.
_is_hotspot = true; _is_hotspot = true;
_env = NULL;
return; return;
} }
if (parent_env != NULL) { if (parent_env != NULL) {
// If the parent JNI environment is non-null then figure out whether it // If the parent JNI environment is non-null then figure out whether it
// is a HotSpot or shared library JNIEnv and set the state appropriately. // is a HotSpot or shared library JNIEnv and set the state appropriately.
JavaThread* thread = JavaThread::current(); _is_hotspot = thread->jni_environment() == parent_env;
if (thread->jni_environment() == parent_env) { if (_is_hotspot) {
// Select the Java runtime // Select the Java runtime
_runtime = JVMCI::java_runtime(); _runtime = JVMCI::java_runtime();
_is_hotspot = true;
_env = NULL;
return; return;
} }
_env = parent_env;
return;
} }
// Running in JVMCI shared library mode so get a shared library JNIEnv // Running in JVMCI shared library mode so ensure the shared library
// is loaded and initialized and get a shared library JNIEnv
_is_hotspot = false; _is_hotspot = false;
_env = attach_shared_library(); _env = init_shared_library(thread);
assert(parent_env == NULL || _env == parent_env, "must be");
if (parent_env == NULL) { if (_env != NULL) {
// There is no parent shared library JNI env so push // Creating the JVMCI shared library VM also attaches the current thread
// a JNI local frame to release all local handles in _detach_on_close = true;
// this JVMCIEnv scope when it's closed. } else {
assert(_throw_to_caller == false, "must be"); _shared_library_javavm->GetEnv((void**)&parent_env, JNI_VERSION_1_2);
JNIAccessMark jni(this); if (parent_env != NULL) {
jint result = _env->PushLocalFrame(32); // Even though there's a parent JNI env, there's no guarantee
if (result != JNI_OK) { // it was opened by a JVMCIEnv scope and thus may not have
char message[256]; // pushed a local JNI frame. As such, we use a new JNI local
jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line); // frame in this scope to ensure local JNI refs are collected
JVMCIRuntime::exit_on_pending_exception(this, message); // in a timely manner after leaving this scope.
_env = parent_env;
} else {
ResourceMark rm; // Thread name is resource allocated
JavaVMAttachArgs attach_args;
attach_args.version = JNI_VERSION_1_2;
attach_args.name = thread->name();
attach_args.group = NULL;
if (_shared_library_javavm->AttachCurrentThread((void**)&_env, &attach_args) != JNI_OK) {
fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name);
}
_detach_on_close = true;
} }
} }
assert(_env != NULL, "missing env");
assert(_throw_to_caller == false, "must be");
JNIAccessMark jni(this);
jint result = _env->PushLocalFrame(32);
if (result != JNI_OK) {
char message[256];
jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line);
JVMCIRuntime::exit_on_pending_exception(this, message);
}
_pop_frame_on_close = true;
} }
JVMCIEnv::JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line): JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line):
_throw_to_caller(false), _file(file), _line(line), _compile_state(compile_state) { _throw_to_caller(false), _file(file), _line(line), _compile_state(compile_state) {
init_env_mode_runtime(NULL); init_env_mode_runtime(thread, NULL);
} }
JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line):
_throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) { _throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) {
init_env_mode_runtime(NULL); init_env_mode_runtime(thread, NULL);
} }
JVMCIEnv::JVMCIEnv(JNIEnv* parent_env, const char* file, int line): JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line):
_throw_to_caller(true), _file(file), _line(line), _compile_state(NULL) { _throw_to_caller(true), _file(file), _line(line), _compile_state(NULL) {
init_env_mode_runtime(parent_env); init_env_mode_runtime(thread, parent_env);
assert(_env == NULL || parent_env == _env, "mismatched JNIEnvironment"); assert(_env == NULL || parent_env == _env, "mismatched JNIEnvironment");
} }
void JVMCIEnv::init(bool is_hotspot, const char* file, int line) { void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int line) {
_compile_state = NULL; _compile_state = NULL;
_throw_to_caller = false; _throw_to_caller = false;
_file = file; _file = file;
_line = line; _line = line;
if (is_hotspot) { if (is_hotspot) {
_env = NULL; _env = NULL;
_pop_frame_on_close = false;
_detach_on_close = false;
_is_hotspot = true; _is_hotspot = true;
_runtime = JVMCI::java_runtime(); _runtime = JVMCI::java_runtime();
} else { } else {
init_env_mode_runtime(NULL); init_env_mode_runtime(thread, NULL);
} }
} }
@ -324,7 +345,7 @@ JVMCIEnv::~JVMCIEnv() {
} }
} }
} else { } else {
if (!is_hotspot()) { if (_pop_frame_on_close) {
// Pop the JNI local frame that was pushed when entering this JVMCIEnv scope. // Pop the JNI local frame that was pushed when entering this JVMCIEnv scope.
JNIAccessMark jni(this); JNIAccessMark jni(this);
jni()->PopLocalFrame(NULL); jni()->PopLocalFrame(NULL);
@ -335,6 +356,10 @@ JVMCIEnv::~JVMCIEnv() {
jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line); jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line);
JVMCIRuntime::exit_on_pending_exception(this, message); JVMCIRuntime::exit_on_pending_exception(this, message);
} }
if (_detach_on_close) {
get_shared_library_javavm()->DetachCurrentThread();
}
} }
} }
@ -463,26 +488,38 @@ void JVMCIEnv::put_long_at(JVMCIPrimitiveArray array, int index, jlong value) {
} }
} }
void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes) { void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length) {
if (size_in_bytes == 0) { if (length == 0) {
return; return;
} }
if (is_hotspot()) { if (is_hotspot()) {
memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), size_in_bytes); memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), length);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this);
jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, size_in_bytes, dest); jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, length, dest);
} }
} }
void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes) { void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
if (size_in_bytes == 0) { if (length == 0) {
return; return;
} }
if (is_hotspot()) { if (is_hotspot()) {
memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, size_in_bytes); memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, length);
} else { } else {
JNIAccessMark jni(this); JNIAccessMark jni(this);
jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, size_in_bytes, src); jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, length, src);
}
}
void JVMCIEnv::copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
if (length == 0) {
return;
}
if (is_hotspot()) {
memcpy(HotSpotJVMCI::resolve(dest)->long_at_addr(offset), src, length * sizeof(jlong));
} else {
JNIAccessMark jni(this);
jni()->SetLongArrayRegion(dest.as_jlongArray(), offset, length, src);
} }
} }
@ -612,6 +649,8 @@ DO_THROW(NullPointerException)
DO_THROW(IllegalArgumentException) DO_THROW(IllegalArgumentException)
DO_THROW(InvalidInstalledCodeException) DO_THROW(InvalidInstalledCodeException)
DO_THROW(UnsatisfiedLinkError) DO_THROW(UnsatisfiedLinkError)
DO_THROW(UnsupportedOperationException)
DO_THROW(ClassNotFoundException)
#undef DO_THROW #undef DO_THROW
@ -888,7 +927,7 @@ JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci,
return JVMCIObject(); return JVMCIObject();
} }
jobject file_name = NULL; jobject file_name = NULL;
if (file_name != NULL) { if (file_name_sym != NULL) {
file_name = jni()->NewStringUTF(file_name_sym->as_C_string()); file_name = jni()->NewStringUTF(file_name_sym->as_C_string());
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); return JVMCIObject();
@ -1323,14 +1362,15 @@ Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type"); assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type");
oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant)); oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant));
return Handle(THREAD, obj); return Handle(THREAD, obj);
} else { } else if (isa_IndirectHotSpotObjectConstantImpl(constant)) {
assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type");
jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant); jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant);
oop result = resolve_handle(object_handle); oop result = resolve_handle(object_handle);
if (result == NULL) { if (result == NULL) {
JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle()); JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());
} }
return Handle(THREAD, result); return Handle(THREAD, result);
} else {
JVMCI_THROW_MSG_(IllegalArgumentException, "DirectHotSpotObjectConstantImpl shouldn't reach JVMCI in SVM mode", Handle());
} }
} }

View file

@ -36,15 +36,6 @@ class JVMCIPrimitiveArray;
class JVMCICompiler; class JVMCICompiler;
class JVMCIRuntime; class JVMCIRuntime;
// Bring the JVMCI compiler thread into the VM state.
#define JVMCI_VM_ENTRY_MARK \
JavaThread* thread = JavaThread::current(); \
ThreadInVMfromNative __tiv(thread); \
ResetNoHandleMark rnhm; \
HandleMarkCleaner __hm(thread); \
Thread* THREAD = thread; \
debug_only(VMNativeEntryWrapper __vew;)
#define JVMCI_EXCEPTION_CONTEXT \ #define JVMCI_EXCEPTION_CONTEXT \
JavaThread* thread=JavaThread::current(); \ JavaThread* thread=JavaThread::current(); \
Thread* THREAD = thread; Thread* THREAD = thread;
@ -154,24 +145,25 @@ class JVMCIEnv : public ResourceObj {
static void* _shared_library_handle; // result of 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 static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library
// Attaches the current thread to the JavaVM in the shared library, // Initializes the shared library JavaVM if not already initialized.
// initializing the shared library VM first if necessary. // Returns the JNI interface pointer for the current thread
// Returns the JNI interface pointer of the current thread. // if initialization was performed by this call, NULL if
// The _shared_library_* fields are initialized by the first // initialization was performed by a previous call.
// call to this method. static JNIEnv* init_shared_library(JavaThread* thread);
static JNIEnv* attach_shared_library();
// Initializes the _env, _mode and _runtime fields. // Initializes the _env, _mode and _runtime fields.
void init_env_mode_runtime(JNIEnv* parent_env); void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env);
void init(bool is_hotspot, const char* file, int line); void init(JavaThread* thread, bool is_hotspot, const char* file, int line);
JNIEnv* _env; // JNI env for calling into shared library JNIEnv* _env; // JNI env for calling into shared library
JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime bool _pop_frame_on_close; // Must pop frame on close?
bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in bool _detach_on_close; // Must detach on close?
bool _throw_to_caller; // Propagate an exception raised in this env to the caller? JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime
const char* _file; // The file and ... bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in
int _line; // ... line where this JNIEnv was created bool _throw_to_caller; // Propagate an exception raised in this env to the caller?
const char* _file; // The file and ...
int _line; // ... line where this JNIEnv was created
// Translates an exception on the HotSpot heap to an exception on // Translates an exception on the HotSpot heap to an exception on
// the shared library heap. The translation includes the stack and // the shared library heap. The translation includes the stack and
@ -185,12 +177,12 @@ public:
// scope closes so that it will be propagated back to Java. // scope closes so that it will be propagated back to Java.
// The JVMCIEnv destructor translates the exception object for the // The JVMCIEnv destructor translates the exception object for the
// Java runtime if necessary. // Java runtime if necessary.
JVMCIEnv(JNIEnv* env, const char* file, int line); JVMCIEnv(JavaThread* thread, JNIEnv* env, const char* file, int line);
// Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker. // Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker.
// An exception occurring within the scope must not be propagated back to // An exception occurring within the scope must not be propagated back to
// the CompileBroker. // the CompileBroker.
JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line); JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line);
// Opens a JNIEnv scope for a call from within the VM. An exception occurring // Opens a JNIEnv scope for a call from within the VM. An exception occurring
// within the scope must not be propagated back to the caller. // within the scope must not be propagated back to the caller.
@ -198,20 +190,20 @@ public:
// Opens a JNIEnv scope for accessing `for_object`. An exception occurring // Opens a JNIEnv scope for accessing `for_object`. An exception occurring
// within the scope must not be propagated back to the caller. // within the scope must not be propagated back to the caller.
JVMCIEnv(JVMCIObject for_object, const char* file, int line) { JVMCIEnv(JavaThread* thread, JVMCIObject for_object, const char* file, int line) {
// A JNI call to access an object in the shared library heap // A JNI call to access an object in the shared library heap
// can block or take a long time so do not allow such access // can block or take a long time so do not allow such access
// on the VM thread. // on the VM thread.
assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(), assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(),
"cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object"); "cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object");
init(for_object.is_hotspot(), file, line); init(thread, for_object.is_hotspot(), file, line);
} }
// Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true // Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true
// otherwise for the shared library runtime. An exception occurring // otherwise for the shared library runtime. An exception occurring
// within the scope must not be propagated back to the caller. // within the scope must not be propagated back to the caller.
JVMCIEnv(bool is_hotspot, const char* file, int line) { JVMCIEnv(JavaThread* thread, bool is_hotspot, const char* file, int line) {
init(is_hotspot, file, line); init(thread, is_hotspot, file, line);
} }
~JVMCIEnv(); ~JVMCIEnv();
@ -247,8 +239,10 @@ public:
long get_long_at(JVMCIPrimitiveArray array, int index); long get_long_at(JVMCIPrimitiveArray array, int index);
void put_long_at(JVMCIPrimitiveArray array, int index, jlong value); void put_long_at(JVMCIPrimitiveArray array, int index, jlong value);
void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes); void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length);
void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes); void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length);
void copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length);
JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS); JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS);
@ -323,6 +317,8 @@ public:
DO_THROW(IllegalArgumentException) DO_THROW(IllegalArgumentException)
DO_THROW(InvalidInstalledCodeException) DO_THROW(InvalidInstalledCodeException)
DO_THROW(UnsatisfiedLinkError) DO_THROW(UnsatisfiedLinkError)
DO_THROW(UnsupportedOperationException)
DO_THROW(ClassNotFoundException)
#undef DO_THROW #undef DO_THROW

View file

@ -32,8 +32,8 @@ class JVMCIEnv;
#define JVMCIENV __jvmci_env__ #define JVMCIENV __jvmci_env__
#define JVMCI_TRAPS JVMCIEnv* JVMCIENV #define JVMCI_TRAPS JVMCIEnv* JVMCIENV
#define JNI_JVMCIENV(env) \ #define JNI_JVMCIENV(thread, env) \
JVMCIEnv __stack_jvmci_env__(env, __FILE__, __LINE__); \ JVMCIEnv __stack_jvmci_env__(thread, env, __FILE__, __LINE__); \
JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ JVMCIEnv* JVMCIENV = &__stack_jvmci_env__
#define THREAD_JVMCIENV(thread) \ #define THREAD_JVMCIENV(thread) \

View file

@ -356,6 +356,43 @@ extern "C" {
jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c);
} }
// Dumps symbols for public <init>() and <init>(String) methods of
// non-abstract Throwable subtypes known by the VM. This is to
// support the use of reflection in jdk.vm.ci.hotspot.TranslatedException.create().
class ThrowableInitDumper : public SymbolClosure {
private:
fileStream* _st;
public:
ThrowableInitDumper(fileStream* st) { _st = st; }
void do_symbol(Symbol** p) {
Thread* THREAD = Thread::current();
Symbol* name = *p;
if (name == NULL) {
return;
}
Klass* k = SystemDictionary::resolve_or_null(name, CHECK_EXIT);
if (k != NULL && k->is_instance_klass()) {
InstanceKlass* iklass = InstanceKlass::cast(k);
if (iklass->is_subclass_of(SystemDictionary::Throwable_klass()) && iklass->is_public() && !iklass->is_abstract()) {
const char* class_name = NULL;
Array<Method*>* methods = iklass->methods();
for (int i = 0; i < methods->length(); i++) {
Method* m = methods->at(i);
if (m->name() == vmSymbols::object_initializer_name() &&
m->is_public() &&
(m->signature() == vmSymbols::void_method_signature() || m->signature() == vmSymbols::string_void_signature())) {
if (class_name == NULL) {
class_name = name->as_C_string();
_st->print_cr("class %s", class_name);
}
_st->print_cr("method %s %s %s", class_name, m->name()->as_C_string(), m->signature()->as_C_string());
}
}
}
}
}
};
#define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string() #define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string()
/** /**
* Initializes the JNI method and field ids used in JNIJVMCI. * Initializes the JNI method and field ids used in JNIJVMCI.
@ -441,6 +478,8 @@ void JNIJVMCI::initialize_ids(JNIEnv* env) {
fileStream* st = JVMCIGlobals::get_jni_config_file(); fileStream* st = JVMCIGlobals::get_jni_config_file();
DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM()); DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM());
ThrowableInitDumper dumper(st);
vmSymbols::symbols_do(&dumper);
st->flush(); st->flush();
tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig); tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig);

View file

@ -381,12 +381,18 @@
start_class(InternalError, java_lang_InternalError) \ start_class(InternalError, java_lang_InternalError) \
jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \ jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \
end_class \ end_class \
start_class(ClassNotFoundException, java_lang_ClassNotFoundException) \
jvmci_constructor(ClassNotFoundException, "(Ljava/lang/String;)V") \
end_class \
start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \ start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \
jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \ jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \
end_class \ end_class \
start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \ start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \
jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \ jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \
end_class \ end_class \
start_class(UnsupportedOperationException, java_lang_UnsupportedOperationException) \
jvmci_constructor(UnsupportedOperationException, "(Ljava/lang/String;)V") \
end_class \
start_class(StackTraceElement, java_lang_StackTraceElement) \ start_class(StackTraceElement, java_lang_StackTraceElement) \
object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \ object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \
object_field(StackTraceElement, methodName, "Ljava/lang/String;") \ object_field(StackTraceElement, methodName, "Ljava/lang/String;") \

View file

@ -655,7 +655,7 @@ JRT_END
// private static JVMCIRuntime JVMCI.initializeRuntime() // private static JVMCIRuntime JVMCI.initializeRuntime()
JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
JNI_JVMCIENV(env); JNI_JVMCIENV(thread, env);
if (!EnableJVMCI) { if (!EnableJVMCI) {
JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled"); JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled");
} }
@ -877,7 +877,7 @@ JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass))
fatal("check TLAB allocation code for address space conflicts"); fatal("check TLAB allocation code for address space conflicts");
#endif #endif
JNI_JVMCIENV(env); JNI_JVMCIENV(thread, env);
if (!EnableJVMCI) { if (!EnableJVMCI) {
JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled"); JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled");
@ -1353,6 +1353,10 @@ void JVMCIRuntime::compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, c
compile_state->set_failure(true, "No OSR during boostrap"); compile_state->set_failure(true, "No OSR during boostrap");
return; return;
} }
if (JVMCI::shutdown_called()) {
compile_state->set_failure(false, "Avoiding compilation during shutdown");
return;
}
HandleMark hm; HandleMark hm;
JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV); JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV);

View file

@ -83,7 +83,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() {
} }
FLAG_SET_DEFAULT(EnableJVMCI, true); FLAG_SET_DEFAULT(EnableJVMCI, true);
if (BootstrapJVMCI && UseJVMCINativeLibrary) { if (BootstrapJVMCI && UseJVMCINativeLibrary) {
jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary"); jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary\n");
return false; return false;
} }
} }

View file

@ -53,7 +53,10 @@
"Prints properties used by the JVMCI compiler and exits") \ "Prints properties used by the JVMCI compiler and exits") \
\ \
experimental(bool, BootstrapJVMCI, false, \ experimental(bool, BootstrapJVMCI, false, \
"Bootstrap JVMCI before running Java main method") \ "Bootstrap JVMCI before running Java main method. This " \
"initializes the compile queue with a small set of methods " \
"and processes the queue until it is empty. Combining this with " \
"-XX:-TieredCompilation makes JVMCI compile more of itself.") \
\ \
experimental(bool, EagerJVMCI, false, \ experimental(bool, EagerJVMCI, false, \
"Force eager JVMCI initialization") \ "Force eager JVMCI initialization") \

View file

@ -246,6 +246,10 @@
\ \
nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \ nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \
\ \
volatile_nonstatic_field(ObjectMonitor, _cxq, ObjectWaiter*) \
volatile_nonstatic_field(ObjectMonitor, _EntryList, ObjectWaiter*) \
volatile_nonstatic_field(ObjectMonitor, _succ, Thread*) \
\
volatile_nonstatic_field(oopDesc, _mark, markOop) \ volatile_nonstatic_field(oopDesc, _mark, markOop) \
volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \
\ \
@ -347,6 +351,7 @@
declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(JVMCIEnv) \
declare_toplevel_type(LocalVariableTableElement) \ declare_toplevel_type(LocalVariableTableElement) \
declare_toplevel_type(narrowKlass) \ declare_toplevel_type(narrowKlass) \
declare_toplevel_type(ObjectWaiter) \
declare_toplevel_type(Symbol*) \ declare_toplevel_type(Symbol*) \
declare_toplevel_type(vtableEntry) \ declare_toplevel_type(vtableEntry) \
\ \

View file

@ -139,6 +139,7 @@ class ObjectMonitor {
friend class ObjectSynchronizer; friend class ObjectSynchronizer;
friend class ObjectWaiter; friend class ObjectWaiter;
friend class VMStructs; friend class VMStructs;
JVMCI_ONLY(friend class JVMCIVMStructs;)
volatile markOop _header; // displaced object header word - mark volatile markOop _header; // displaced object header word - mark
void* volatile _object; // backward object pointer - strong root void* volatile _object; // backward object pointer - strong root

View file

@ -1575,18 +1575,15 @@ bool jvmci_counters_include(JavaThread* thread) {
return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread();
} }
void JavaThread::collect_counters(JVMCIEnv* jvmci_env, JVMCIPrimitiveArray array) { void JavaThread::collect_counters(jlong* array, int length) {
if (JVMCICounterSize > 0) { assert(length == JVMCICounterSize, "wrong value");
JavaThreadIteratorWithHandle jtiwh; for (int i = 0; i < length; i++) {
int len = jvmci_env->get_length(array); array[i] = _jvmci_old_thread_counters[i];
for (int i = 0; i < len; i++) { }
jvmci_env->put_long_at(array, i, _jvmci_old_thread_counters[i]); for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) {
} if (jvmci_counters_include(tp)) {
for (; JavaThread *tp = jtiwh.next(); ) { for (int i = 0; i < length; i++) {
if (jvmci_counters_include(tp)) { array[i] += tp->_jvmci_counters[i];
for (int i = 0; i < len; i++) {
jvmci_env->put_long_at(array, i, jvmci_env->get_long_at(array, i) + tp->_jvmci_counters[i]);
}
} }
} }
} }

View file

@ -1152,7 +1152,7 @@ class JavaThread: public Thread {
public: public:
static jlong* _jvmci_old_thread_counters; static jlong* _jvmci_old_thread_counters;
static void collect_counters(JVMCIEnv* JVMCIENV, JVMCIPrimitiveArray array); static void collect_counters(jlong* array, int length);
private: private:
#endif // INCLUDE_JVMCI #endif // INCLUDE_JVMCI

View file

@ -438,14 +438,14 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
if (thr->is_Compiler_thread()) { if (thr->is_Compiler_thread()) {
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
CompilerThread* ct = (CompilerThread*) thr; CompilerThread* ct = (CompilerThread*) thr;
if (ct->compiler() == NULL || !ct->compiler()->is_jvmci() || !UseJVMCINativeLibrary) { if (ct->compiler() == NULL || !ct->compiler()->is_jvmci()) {
num_active_compiler_thread++; num_active_compiler_thread++;
} else { } else {
// When using a compiler in a JVMCI shared library, it's possible // A JVMCI compiler thread never accesses VM data structures
// for one compiler thread to grab a lock in the shared library, // while in _thread_in_native state so there's no need to wait
// enter HotSpot and go to sleep on the shutdown safepoint. Another // for it and potentially add a 300 millisecond delay to VM
// JVMCI shared library compiler thread can then attempt to grab the // shutdown.
// lock and thus never make progress. num_active--;
} }
#else #else
num_active_compiler_thread++; num_active_compiler_thread++;

View file

@ -612,10 +612,15 @@ final class CompilerToVM {
* Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's
* log stream. * log stream.
* *
* @param flush specifies if the log stream should be flushed after writing
* @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length}
* arguments should result in an exception or a negative return value
* @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and
* copying would cause access of data outside array bounds
* @throws NullPointerException if {@code bytes == null} * @throws NullPointerException if {@code bytes == null}
* @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds
*/ */
native void writeDebugOutput(byte[] bytes, int offset, int length); native int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow);
/** /**
* Flush HotSpot's log stream. * Flush HotSpot's log stream.
@ -947,4 +952,18 @@ final class CompilerToVM {
*/ */
native boolean addFailedSpeculation(long failedSpeculationsAddress, byte[] speculation); native boolean addFailedSpeculation(long failedSpeculationsAddress, byte[] speculation);
/**
* @see HotSpotJVMCIRuntime#isCurrentThreadAttached()
*/
native boolean isCurrentThreadAttached();
/**
* @see HotSpotJVMCIRuntime#attachCurrentThread
*/
native boolean attachCurrentThread(boolean asDaemon);
/**
* @see HotSpotJVMCIRuntime#detachCurrentThread()
*/
native void detachCurrentThread();
} }

View file

@ -46,7 +46,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.TreeMap;
import java.util.function.Predicate; import java.util.function.Predicate;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
@ -180,8 +179,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
// Can only do eager initialization of the JVMCI compiler // Can only do eager initialization of the JVMCI compiler
// once the singleton instance is available. // once the singleton instance is available.
if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { if (result.config.getFlag("EagerJVMCI", Boolean.class)) {
instance.getCompiler(); result.getCompiler();
} }
} }
// Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is
@ -464,7 +463,7 @@ assert factories != null : "sanity";
} }
if (Option.PrintConfig.getBoolean()) { if (Option.PrintConfig.getBoolean()) {
printConfig(configStore, compilerToVm); configStore.printConfig();
} }
} }
@ -727,39 +726,21 @@ assert factories != null : "sanity";
} }
} }
@SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!") /**
private static void printConfigLine(CompilerToVM vm, String format, Object... args) { * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's
String line = String.format(format, args); * log stream.
byte[] lineBytes = line.getBytes(); *
vm.writeDebugOutput(lineBytes, 0, lineBytes.length); * @param flush specifies if the log stream should be flushed after writing
vm.flushDebugOutput(); * @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length}
} * arguments should result in an exception or a negative return value. If
* {@code false}, this call will not perform any heap allocation
private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) { * @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and
TreeMap<String, VMField> fields = new TreeMap<>(store.getFields()); * copying would cause access of data outside array bounds
for (VMField field : fields.values()) { * @throws NullPointerException if {@code bytes == null}
if (!field.isStatic()) { * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds
printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset); */
} else { public int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow) {
String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value); return compilerToVm.writeDebugOutput(bytes, offset, length, flush, canThrow);
printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address);
}
}
TreeMap<String, VMFlag> flags = new TreeMap<>(store.getFlags());
for (VMFlag flag : flags.values()) {
printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value);
}
TreeMap<String, Long> addresses = new TreeMap<>(store.getAddresses());
for (Map.Entry<String, Long> e : addresses.entrySet()) {
printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
}
TreeMap<String, Long> constants = new TreeMap<>(store.getConstants());
for (Map.Entry<String, Long> e : constants.entrySet()) {
printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
}
for (VMIntrinsicMethod e : store.getIntrinsics()) {
printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor);
}
} }
/** /**
@ -777,7 +758,7 @@ assert factories != null : "sanity";
} else if (len == 0) { } else if (len == 0) {
return; return;
} }
compilerToVm.writeDebugOutput(b, off, len); compilerToVm.writeDebugOutput(b, off, len, false, true);
} }
@Override @Override
@ -907,11 +888,13 @@ assert factories != null : "sanity";
* the Java VM in the JVMCI shared library, and the remaining values are the first 3 * the Java VM in the JVMCI shared library, and the remaining values are the first 3
* pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface})
* @throws NullPointerException if {@code clazz == null} * @throws NullPointerException if {@code clazz == null}
* @throws IllegalArgumentException if the current execution context is the JVMCI shared library * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* or if {@code clazz} is {@link Class#isPrimitive()} * {@code -XX:-UseJVMCINativeLibrary})
* @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in * @throws IllegalStateException if the current execution context is the JVMCI shared library
* {@code clazz} is already linked or the JVMCI shared library does not contain a * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()}
* JNI-compatible symbol for a native method in {@code clazz} * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz}
* (no matching JNI symbol or the native method is already linked to a different
* address)
*/ */
public long[] registerNativeMethods(Class<?> clazz) { public long[] registerNativeMethods(Class<?> clazz) {
return compilerToVm.registerNativeMethods(clazz); return compilerToVm.registerNativeMethods(clazz);
@ -935,6 +918,8 @@ assert factories != null : "sanity";
* *
* @param obj an object for which an equivalent instance in the peer runtime is requested * @param obj an object for which an equivalent instance in the peer runtime is requested
* @return a JNI global reference to the mirror of {@code obj} in the peer runtime * @return a JNI global reference to the mirror of {@code obj} in the peer runtime
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalArgumentException if {@code obj} is not of a translatable type * @throws IllegalArgumentException if {@code obj} is not of a translatable type
* *
* @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
@ -950,7 +935,9 @@ assert factories != null : "sanity";
* *
* @param handle a JNI global reference to an object in the current runtime * @param handle a JNI global reference to an object in the current runtime
* @return the object referred to by {@code handle} * @return the object referred to by {@code handle}
* @throws ClassCastException if the returned object cannot be case to {@code type} * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws ClassCastException if the returned object cannot be cast to {@code type}
* *
* @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
* *
@ -959,6 +946,44 @@ assert factories != null : "sanity";
return type.cast(compilerToVm.unhand(handle)); return type.cast(compilerToVm.unhand(handle));
} }
/**
* Determines if the current thread is attached to the peer runtime.
*
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the peer runtime has not been initialized
*/
public boolean isCurrentThreadAttached() {
return compilerToVm.isCurrentThreadAttached();
}
/**
* Ensures the current thread is attached to the peer runtime.
*
* @param asDaemon if the thread is not yet attached, should it be attached as a daemon
* @return {@code true} if this call attached the current thread, {@code false} if the current
* thread was already attached
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the peer runtime has not been initialized or there is an
* error while trying to attach the thread
*/
public boolean attachCurrentThread(boolean asDaemon) {
return compilerToVm.attachCurrentThread(asDaemon);
}
/**
* Detaches the current thread from the peer runtime.
*
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the peer runtime has not been initialized or if the current
* thread is not attached or if there is an error while trying to detach the thread
*/
public void detachCurrentThread() {
compilerToVm.detachCurrentThread();
}
/** /**
* Informs HotSpot that no method whose module is in {@code modules} is to be compiled * Informs HotSpot that no method whose module is in {@code modules} is to be compiled
* with {@link #compileMethod}. * with {@link #compileMethod}.

View file

@ -193,8 +193,7 @@ public final class HotSpotVMConfigStore {
private static void printConfigLine(CompilerToVM vm, String format, Object... args) { private static void printConfigLine(CompilerToVM vm, String format, Object... args) {
String line = String.format(format, args); String line = String.format(format, args);
byte[] lineBytes = line.getBytes(); byte[] lineBytes = line.getBytes();
vm.writeDebugOutput(lineBytes, 0, lineBytes.length); vm.writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
vm.flushDebugOutput();
} }
} }

View file

@ -49,16 +49,23 @@ final class TranslatedException extends Exception {
return this; return this;
} }
@Override private static Throwable create(String className, String message) {
public String toString() { // Try create with reflection first.
return getMessage(); try {
} Class<?> cls = Class.forName(className);
if (message == null) {
return (Throwable) cls.getConstructor().newInstance();
}
cls.getDeclaredConstructor(String.class);
return (Throwable) cls.getConstructor(String.class).newInstance(message);
} catch (Throwable ignore) {
}
private static TranslatedException create(String className, String message) {
if (className.equals(TranslatedException.class.getName())) { if (className.equals(TranslatedException.class.getName())) {
// Chop the class name when boxing another TranslatedException // Chop the class name when boxing another TranslatedException
return new TranslatedException(message); return new TranslatedException(message);
} }
if (message == null) { if (message == null) {
return new TranslatedException(className); return new TranslatedException(className);
} }
@ -147,7 +154,7 @@ final class TranslatedException extends Exception {
Throwable throwable = create(exceptionClassName, exceptionMessage); Throwable throwable = create(exceptionClassName, exceptionMessage);
int stackTraceDepth = Integer.parseInt(parts[i++]); int stackTraceDepth = Integer.parseInt(parts[i++]);
StackTraceElement[] suffix = parent == null ? new StackTraceElement[0] : getStackTraceSuffix(); StackTraceElement[] suffix = getStackTraceSuffix();
StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length]; StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length];
for (int j = 0; j < stackTraceDepth; j++) { for (int j = 0; j < stackTraceDepth; j++) {
String className = parts[i++]; String className = parts[i++];

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2019, 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
@ -38,13 +38,13 @@ public class MetaUtil {
* @return the simple name * @return the simple name
*/ */
public static String getSimpleName(Class<?> clazz, boolean withEnclosingClass) { public static String getSimpleName(Class<?> clazz, boolean withEnclosingClass) {
final String simpleName = clazz.getSimpleName(); final String simpleName = safeSimpleName(clazz);
if (simpleName.length() != 0) { if (simpleName.length() != 0) {
if (withEnclosingClass) { if (withEnclosingClass) {
String prefix = ""; String prefix = "";
Class<?> enclosingClass = clazz; Class<?> enclosingClass = clazz;
while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) { while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) {
prefix = enclosingClass.getSimpleName() + "." + prefix; prefix = safeSimpleName(enclosingClass) + "." + prefix;
} }
return prefix + simpleName; return prefix + simpleName;
} }
@ -63,6 +63,29 @@ public class MetaUtil {
return name.substring(index + 1); return name.substring(index + 1);
} }
private static String safeSimpleName(Class<?> clazz) {
try {
return clazz.getSimpleName();
} catch (InternalError e) {
// Scala inner class names do not always start with '$',
// causing Class.getSimpleName to throw an InternalError
Class<?> enclosingClass = clazz.getEnclosingClass();
String fqn = clazz.getName();
if (enclosingClass == null) {
// Should never happen given logic in
// Class.getSimpleName but best be safe
return fqn;
}
String enclosingFQN = enclosingClass.getName();
int length = fqn.length();
if (enclosingFQN.length() >= length) {
// Should also never happen
return fqn;
}
return fqn.substring(enclosingFQN.length());
}
}
/** /**
* Converts a type name in internal form to an external form. * Converts a type name in internal form to an external form.
* *

View file

@ -282,6 +282,17 @@ public final class Services {
return ClassLoader.getSystemClassLoader(); return ClassLoader.getSystemClassLoader();
} }
/**
* A Java {@code char} has a maximal UTF8 length of 3.
*/
private static final int MAX_UNICODE_IN_UTF8_LENGTH = 3;
/**
* {@link DataOutputStream#writeUTF(String)} only supports values whose UTF8 encoding length is
* less than 65535.
*/
private static final int MAX_UTF8_PROPERTY_STRING_LENGTH = 65535 / MAX_UNICODE_IN_UTF8_LENGTH;
/** /**
* Serializes the {@linkplain #getSavedProperties() saved system properties} to a byte array for * Serializes the {@linkplain #getSavedProperties() saved system properties} to a byte array for
* the purpose of {@linkplain #initializeSavedProperties(byte[]) initializing} the initial * the purpose of {@linkplain #initializeSavedProperties(byte[]) initializing} the initial
@ -292,25 +303,48 @@ public final class Services {
if (IS_IN_NATIVE_IMAGE) { if (IS_IN_NATIVE_IMAGE) {
throw new InternalError("Can only serialize saved properties in HotSpot runtime"); throw new InternalError("Can only serialize saved properties in HotSpot runtime");
} }
Map<String, String> props = Services.getSavedProperties(); return serializeProperties(Services.getSavedProperties());
}
private static byte[] serializeProperties(Map<String, String> props) throws IOException {
// Compute size of output on the assumption that // Compute size of output on the assumption that
// all system properties have ASCII names and values // all system properties have ASCII names and values
int estimate = 4; int estimate = 4 + 4;
int nonUtf8Props = 0;
for (Map.Entry<String, String> e : props.entrySet()) { for (Map.Entry<String, String> e : props.entrySet()) {
String name = e.getKey(); String name = e.getKey();
String value = e.getValue(); String value = e.getValue();
estimate += (2 + (name.length())) + (2 + (value.length())); estimate += (2 + (name.length())) + (2 + (value.length()));
if (name.length() > MAX_UTF8_PROPERTY_STRING_LENGTH || value.length() > MAX_UTF8_PROPERTY_STRING_LENGTH) {
nonUtf8Props++;
}
} }
ByteArrayOutputStream baos = new ByteArrayOutputStream(estimate); ByteArrayOutputStream baos = new ByteArrayOutputStream(estimate);
DataOutputStream out = new DataOutputStream(baos); DataOutputStream out = new DataOutputStream(baos);
out.writeInt(props.size()); out.writeInt(props.size() - nonUtf8Props);
out.writeInt(nonUtf8Props);
for (Map.Entry<String, String> e : props.entrySet()) { for (Map.Entry<String, String> e : props.entrySet()) {
String name = e.getKey(); String name = e.getKey();
String value = e.getValue(); String value = e.getValue();
out.writeUTF(name); if (name.length() <= MAX_UTF8_PROPERTY_STRING_LENGTH && value.length() <= MAX_UTF8_PROPERTY_STRING_LENGTH) {
out.writeUTF(value); out.writeUTF(name);
out.writeUTF(value);
}
}
if (nonUtf8Props != 0) {
for (Map.Entry<String, String> e : props.entrySet()) {
String name = e.getKey();
String value = e.getValue();
if (name.length() > MAX_UTF8_PROPERTY_STRING_LENGTH || value.length() > MAX_UTF8_PROPERTY_STRING_LENGTH) {
byte[] utf8Name = name.getBytes("UTF-8");
byte[] utf8Value = value.getBytes("UTF-8");
out.writeInt(utf8Name.length);
out.write(utf8Name);
out.writeInt(utf8Value.length);
out.write(utf8Value);
}
}
} }
return baos.toByteArray(); return baos.toByteArray();
} }
@ -325,13 +359,33 @@ public final class Services {
if (!IS_IN_NATIVE_IMAGE) { if (!IS_IN_NATIVE_IMAGE) {
throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime"); throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime");
} }
savedProperties = Collections.unmodifiableMap(deserializeProperties(serializedProperties));
}
private static Map<String, String> deserializeProperties(byte[] serializedProperties) throws IOException {
DataInputStream in = new DataInputStream(new ByteArrayInputStream(serializedProperties)); DataInputStream in = new DataInputStream(new ByteArrayInputStream(serializedProperties));
Map<String, String> props = new HashMap<>(in.readInt()); int utf8Props = in.readInt();
int nonUtf8Props = in.readInt();
Map<String, String> props = new HashMap<>(utf8Props + nonUtf8Props);
int index = 0;
while (in.available() != 0) { while (in.available() != 0) {
String name = in.readUTF(); if (index < utf8Props) {
String value = in.readUTF(); String name = in.readUTF();
props.put(name, value); String value = in.readUTF();
props.put(name, value);
} else {
int nameLen = in.readInt();
byte[] nameBytes = new byte[nameLen];
in.read(nameBytes);
int valueLen = in.readInt();
byte[] valueBytes = new byte[valueLen];
in.read(valueBytes);
String name = new String(nameBytes, "UTF-8");
String value = new String(valueBytes, "UTF-8");
props.put(name, value);
}
index++;
} }
savedProperties = Collections.unmodifiableMap(props); return props;
} }
} }

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.vm.ci.services;
/**
* Used to suppress <a href="http://findbugs.sourceforge.net">FindBugs</a> warnings.
*/
@interface SuppressFBWarnings {
/**
* The set of FindBugs
* <a href="http://findbugs.sourceforge.net/bugDescriptions.html">warnings</a> that are to be
* suppressed in annotated element. The value can be a bug category, kind or pattern.
*/
String[] value();
/**
* Reason why the warning is suppressed.
*/
String justification();
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, 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
@ -30,6 +30,9 @@ module jdk.internal.vm.ci {
exports jdk.vm.ci.runtime to exports jdk.vm.ci.runtime to
jdk.internal.vm.compiler, jdk.internal.vm.compiler,
jdk.internal.vm.compiler.management; jdk.internal.vm.compiler.management;
exports jdk.vm.ci.meta to jdk.internal.vm.compiler;
exports jdk.vm.ci.code to jdk.internal.vm.compiler;
exports jdk.vm.ci.hotspot to jdk.internal.vm.compiler;
uses jdk.vm.ci.services.JVMCIServiceLocator; uses jdk.vm.ci.services.JVMCIServiceLocator;
uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory;

View file

@ -43,6 +43,7 @@ import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.nodes.util.GraphUtil;
import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant;
import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.Constant;
@ -83,7 +84,7 @@ public class LoadConstantIndirectlyNode extends FloatingNode implements Canonica
public void generate(NodeLIRBuilderTool gen) { public void generate(NodeLIRBuilderTool gen) {
assert constant != null : "Expected the value to fold: " + value; assert constant != null : "Expected the value to fold: " + value;
Value result; Value result;
if (constant instanceof HotSpotObjectConstant) { if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) {
result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant); result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant);
} else if (constant instanceof HotSpotMetaspaceConstant) { } else if (constant instanceof HotSpotMetaspaceConstant) {
result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action); result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action);

View file

@ -45,6 +45,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.Word;
import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant;
import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.Constant;
@ -100,7 +101,7 @@ public class ResolveConstantStubCall extends DeoptimizingStubCall implements Can
Value result; Value result;
LIRFrameState fs = gen.state(this); LIRFrameState fs = gen.state(this);
assert fs != null : "The stateAfter is null"; assert fs != null : "The stateAfter is null";
if (constant instanceof HotSpotObjectConstant) { if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) {
result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs); result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs);
} else if (constant instanceof HotSpotMetaspaceConstant) { } else if (constant instanceof HotSpotMetaspaceConstant) {
if (action == HotSpotConstantLoadAction.RESOLVE) { if (action == HotSpotConstantLoadAction.RESOLVE) {

View file

@ -301,7 +301,7 @@ public class CompilerToVMHelper {
} }
public static void writeDebugOutput(byte[] bytes, int offset, int length) { public static void writeDebugOutput(byte[] bytes, int offset, int length) {
CTVM.writeDebugOutput(bytes, offset, length); CTVM.writeDebugOutput(bytes, offset, length, true, true);
} }
public static void flushDebugOutput() { public static void flushDebugOutput() {

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.vm.ci.hotspot.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaType;
public class TestHotSpotJVMCIRuntime {
@Test
public void writeDebugOutputTest() {
HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
expectWriteDebugOutputFailure(runtime, null, 0, 0, true, true, NullPointerException.class);
expectWriteDebugOutputFailure(runtime, null, 0, 0, true, false, -1);
byte[] emptyOutput = {};
byte[] nonEmptyOutput = String.format("non-empty output%n").getBytes();
for (boolean canThrow : new boolean[]{true, false}) {
for (byte[] output : new byte[][]{emptyOutput, nonEmptyOutput}) {
for (int offset = 0; offset < output.length; offset++) {
int length = output.length - offset;
runtime.writeDebugOutput(output, offset, length, true, canThrow);
}
Object expect = canThrow ? IndexOutOfBoundsException.class : -2;
expectWriteDebugOutputFailure(runtime, output, output.length + 1, 0, true, canThrow, expect);
expectWriteDebugOutputFailure(runtime, output, 0, output.length + 1, true, canThrow, expect);
expectWriteDebugOutputFailure(runtime, output, -1, 0, true, canThrow, expect);
expectWriteDebugOutputFailure(runtime, output, 0, -1, true, canThrow, expect);
}
}
}
private static void expectWriteDebugOutputFailure(HotSpotJVMCIRuntime runtime, byte[] bytes, int offset, int length, boolean flush, boolean canThrow, Object expect) {
try {
int result = runtime.writeDebugOutput(bytes, offset, length, flush, canThrow);
if (expect instanceof Integer) {
Assert.assertEquals((int) expect, result);
} else {
Assert.fail("expected " + expect + ", got " + result + " for bytes == " + Arrays.toString(bytes));
}
} catch (Exception e) {
if (expect instanceof Integer) {
Assert.fail("expected " + expect + ", got " + e + " for bytes == " + Arrays.toString(bytes));
} else {
Assert.assertTrue(e.toString(), ((Class<?>) expect).isInstance(e));
}
}
}
@Test
public void getIntrinsificationTrustPredicateTest() throws Exception {
HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess();
Predicate<ResolvedJavaType> predicate = runtime.getIntrinsificationTrustPredicate(HotSpotJVMCIRuntime.class);
List<Class<?>> classes = new ArrayList<>(Arrays.asList(
Object.class,
String.class,
Class.class,
HotSpotJVMCIRuntime.class,
VirtualObjectLayoutTest.class,
TestHotSpotJVMCIRuntime.class));
try {
classes.add(Class.forName("com.sun.crypto.provider.AESCrypt"));
classes.add(Class.forName("com.sun.crypto.provider.CipherBlockChaining"));
} catch (ClassNotFoundException e) {
// Extension classes not available
}
ClassLoader jvmciLoader = HotSpotJVMCIRuntime.class.getClassLoader();
ClassLoader extLoader = getExtensionLoader();
for (Class<?> c : classes) {
ClassLoader cl = c.getClassLoader();
boolean expected = cl == null || cl == jvmciLoader || cl == extLoader;
boolean actual = predicate.test(metaAccess.lookupJavaType(c));
Assert.assertEquals(c + ": cl=" + cl, expected, actual);
}
}
private static ClassLoader getExtensionLoader() throws Exception {
Object launcher = Class.forName("sun.misc.Launcher").getMethod("getLauncher").invoke(null);
ClassLoader appLoader = (ClassLoader) launcher.getClass().getMethod("getClassLoader").invoke(launcher);
ClassLoader extLoader = appLoader.getParent();
assert extLoader.getClass().getName().equals("sun.misc.Launcher$ExtClassLoader") : extLoader;
return extLoader;
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.vm.ci.hotspot.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.services.Services;
public class TestServices {
@SuppressWarnings("unchecked")
@Test
public void serializeSavedPropertiesTest() throws Exception {
Field f = Services.class.getDeclaredField("MAX_UTF8_PROPERTY_STRING_LENGTH");
f.setAccessible(true);
int maxUtf8PropertyStringLength = (int) f.get(null);
Method serializeProperties = Services.class.getDeclaredMethod("serializeProperties", Map.class);
Method deserializeProperties = Services.class.getDeclaredMethod("deserializeProperties", byte[].class);
serializeProperties.setAccessible(true);
deserializeProperties.setAccessible(true);
Map<String, String> props = new HashMap<>(Services.getSavedProperties());
String[] names = {
new String(new char[maxUtf8PropertyStringLength - 100]).replace('\0', 'x'),
new String(new char[maxUtf8PropertyStringLength - 1]).replace('\0', 'x'),
new String(new char[maxUtf8PropertyStringLength]).replace('\0', 'y'),
new String(new char[maxUtf8PropertyStringLength + 1]).replace('\0', 'z'),
new String(new char[maxUtf8PropertyStringLength + 100]).replace('\0', 'z')
};
String[] values = {
new String(new char[maxUtf8PropertyStringLength - 100]).replace('\0', '1'),
new String(new char[maxUtf8PropertyStringLength - 1]).replace('\0', '1'),
new String(new char[maxUtf8PropertyStringLength]).replace('\0', '2'),
new String(new char[maxUtf8PropertyStringLength + 1]).replace('\0', '1'),
new String(new char[maxUtf8PropertyStringLength + 100]).replace('\0', '3')
};
for (String name : names) {
for (String value : values) {
props.put(name, value);
}
}
byte[] data = (byte[]) serializeProperties.invoke(null, props);
Map<String, String> newProps = (Map<String, String>) deserializeProperties.invoke(null, data);
Assert.assertEquals(props.size(), newProps.size());
for (String name : props.keySet()) {
String expect = props.get(name);
String actual = newProps.get(name);
Assert.assertEquals(expect, actual);
}
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2019, 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
@ -71,6 +71,9 @@ public class JdkQualifiedExportTest {
static Set<String> KNOWN_EXCEPTIONS = static Set<String> KNOWN_EXCEPTIONS =
Set.of("jdk.internal.vm.ci/jdk.vm.ci.services", Set.of("jdk.internal.vm.ci/jdk.vm.ci.services",
"jdk.internal.vm.ci/jdk.vm.ci.runtime", "jdk.internal.vm.ci/jdk.vm.ci.runtime",
"jdk.internal.vm.ci/jdk.vm.ci.hotspot",
"jdk.internal.vm.ci/jdk.vm.ci.meta",
"jdk.internal.vm.ci/jdk.vm.ci.code",
"jdk.jsobject/jdk.internal.netscape.javascript.spi"); "jdk.jsobject/jdk.internal.netscape.javascript.spi");
static void checkExports(ModuleDescriptor md) { static void checkExports(ModuleDescriptor md) {