8298099: [JVMCI] decouple libgraal from JVMCI module at runtime
Reviewed-by: never
This commit is contained in:
parent
8a9911ef17
commit
8b69a2e434
src
hotspot/share
classfile
jvmci
jvmci.cppjvmciCompilerToVM.cppjvmciEnv.cppjvmciEnv.hppjvmciJavaClasses.cppjvmciJavaClasses.hppjvmciRuntime.cppvmSymbols_jvmci.hpp
runtime
java.base/share/classes/jdk/internal/vm
jdk.internal.vm.ci/share/classes
jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot
jdk.vm.ci.services/src/jdk/vm/ci/services
test
hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test
jdk/jdk/internal/vm
@ -671,6 +671,18 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the exploded path for the named module. The memory for the path
|
||||
// is allocated on the C heap if `c_heap` is true otherwise in the resource area.
|
||||
static const char* get_exploded_module_path(const char* module_name, bool c_heap) {
|
||||
const char *home = Arguments::get_java_home();
|
||||
const char file_sep = os::file_separator()[0];
|
||||
// 10 represents the length of "modules" + 2 file separators + \0
|
||||
size_t len = strlen(home) + strlen(module_name) + 10;
|
||||
char *path = c_heap ? NEW_C_HEAP_ARRAY(char, len, mtModule) : NEW_RESOURCE_ARRAY(char, len);
|
||||
jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name);
|
||||
return path;
|
||||
}
|
||||
|
||||
// During an exploded modules build, each module defined to the boot loader
|
||||
// will be added to the ClassLoader::_exploded_entries array.
|
||||
void ClassLoader::add_to_exploded_build_list(JavaThread* current, Symbol* module_sym) {
|
||||
@ -680,12 +692,7 @@ void ClassLoader::add_to_exploded_build_list(JavaThread* current, Symbol* module
|
||||
// Find the module's symbol
|
||||
ResourceMark rm(current);
|
||||
const char *module_name = module_sym->as_C_string();
|
||||
const char *home = Arguments::get_java_home();
|
||||
const char file_sep = os::file_separator()[0];
|
||||
// 10 represents the length of "modules" + 2 file separators + \0
|
||||
size_t len = strlen(home) + strlen(module_name) + 10;
|
||||
char *path = NEW_RESOURCE_ARRAY(char, len);
|
||||
jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name);
|
||||
const char *path = get_exploded_module_path(module_name, false);
|
||||
|
||||
struct stat st;
|
||||
if (os::stat(path, &st) == 0) {
|
||||
@ -1415,6 +1422,20 @@ char* ClassLoader::lookup_vm_options() {
|
||||
return options;
|
||||
}
|
||||
|
||||
bool ClassLoader::is_module_observable(const char* module_name) {
|
||||
assert(JImageOpen != NULL, "jimage library should have been opened");
|
||||
if (JImage_file == NULL) {
|
||||
struct stat st;
|
||||
const char *path = get_exploded_module_path(module_name, true);
|
||||
bool res = os::stat(path, &st) == 0;
|
||||
FREE_C_HEAP_ARRAY(char, path);
|
||||
return res;
|
||||
}
|
||||
jlong size;
|
||||
const char *jimage_version = get_jimage_version_string();
|
||||
return (*JImageFindResource)(JImage_file, module_name, jimage_version, "module-info.class", &size) != 0;
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void ClassLoader::initialize_shared_path(JavaThread* current) {
|
||||
if (Arguments::is_dumping_archive()) {
|
||||
|
@ -374,6 +374,10 @@ class ClassLoader: AllStatic {
|
||||
|
||||
static char* lookup_vm_options();
|
||||
|
||||
// Determines if the named module is present in the
|
||||
// modules jimage file or in the exploded modules directory.
|
||||
static bool is_module_observable(const char* module_name);
|
||||
|
||||
static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
|
||||
const char* file_name, jlong &size);
|
||||
|
||||
|
@ -745,6 +745,10 @@
|
||||
do_alias(appendToClassPathForInstrumentation_signature, string_void_signature) \
|
||||
template(serializePropertiesToByteArray_name, "serializePropertiesToByteArray") \
|
||||
template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
|
||||
template(serializeSavedPropertiesToByteArray_name, "serializeSavedPropertiesToByteArray") \
|
||||
template(encodeThrowable_name, "encodeThrowable") \
|
||||
template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \
|
||||
template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \
|
||||
template(classRedefinedCount_name, "classRedefinedCount") \
|
||||
template(classLoader_name, "classLoader") \
|
||||
template(componentType_name, "componentType") \
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "memory/universe.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/javaThread.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
|
||||
@ -228,9 +229,17 @@ void JVMCI::vlog(int level, const char* format, va_list ap) {
|
||||
void JVMCI::vtrace(int level, const char* format, va_list ap) {
|
||||
if (JVMCITraceLevel >= level) {
|
||||
Thread* thread = Thread::current_or_null_safe();
|
||||
if (thread != nullptr) {
|
||||
ResourceMark rm;
|
||||
tty->print("JVMCITrace-%d[%s]:%*c", level, thread->name(), level, ' ');
|
||||
if (thread != nullptr && thread->is_Java_thread()) {
|
||||
ResourceMark rm(thread);
|
||||
JavaThreadState state = JavaThread::cast(thread)->thread_state();
|
||||
if (state == _thread_in_vm || state == _thread_in_Java || state == _thread_new) {
|
||||
tty->print("JVMCITrace-%d[%s]:%*c", level, thread->name(), level, ' ');
|
||||
} else {
|
||||
// According to check_access_thread_state, it's unsafe to
|
||||
// resolve the j.l.Thread object unless the thread is in
|
||||
// one of the states above.
|
||||
tty->print("JVMCITrace-%d[%s@" PTR_FORMAT "]:%*c", level, thread->type_name(), p2i(thread), level, ' ');
|
||||
}
|
||||
} else {
|
||||
tty->print("JVMCITrace-%d[?]:%*c", level, level, ' ');
|
||||
}
|
||||
|
@ -142,8 +142,8 @@ static JavaThread* get_current_thread(bool allow_null=true) {
|
||||
err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
|
||||
return; \
|
||||
} \
|
||||
JVMCITraceMark jtm("CompilerToVM::" #name); \
|
||||
C2V_BLOCK(result_type, name, signature)
|
||||
C2V_BLOCK(result_type, name, signature) \
|
||||
JVMCITraceMark jtm("CompilerToVM::" #name);
|
||||
|
||||
#define C2V_VMENTRY_(result_type, name, signature, result) \
|
||||
JNIEXPORT result_type JNICALL c2v_ ## name signature { \
|
||||
@ -153,8 +153,8 @@ static JavaThread* get_current_thread(bool allow_null=true) {
|
||||
err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
|
||||
return result; \
|
||||
} \
|
||||
JVMCITraceMark jtm("CompilerToVM::" #name); \
|
||||
C2V_BLOCK(result_type, name, signature)
|
||||
C2V_BLOCK(result_type, name, signature) \
|
||||
JVMCITraceMark jtm("CompilerToVM::" #name);
|
||||
|
||||
#define C2V_VMENTRY_NULL(result_type, name, signature) C2V_VMENTRY_(result_type, name, signature, NULL)
|
||||
#define C2V_VMENTRY_0(result_type, name, signature) C2V_VMENTRY_(result_type, name, signature, 0)
|
||||
@ -503,7 +503,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU
|
||||
} else {
|
||||
// Use the System class loader
|
||||
class_loader = Handle(THREAD, SystemDictionary::java_system_loader());
|
||||
JVMCIENV->runtime()->initialize(JVMCIENV);
|
||||
JVMCIENV->runtime()->initialize(JVMCI_CHECK_NULL);
|
||||
}
|
||||
|
||||
if (resolve) {
|
||||
@ -2312,9 +2312,9 @@ C2V_VMENTRY_PREFIX(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject c2vm
|
||||
// Called from unattached JVMCI shared library thread
|
||||
return false;
|
||||
}
|
||||
JVMCITraceMark jtm("isCurrentThreadAttached");
|
||||
if (thread->jni_environment() == env) {
|
||||
C2V_BLOCK(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject))
|
||||
JVMCITraceMark jtm("isCurrentThreadAttached");
|
||||
requireJVMCINativeLibrary(JVMCI_CHECK_0);
|
||||
JVMCIRuntime* runtime = thread->libjvmci_runtime();
|
||||
if (runtime == nullptr || !runtime->has_shared_library_javavm()) {
|
||||
@ -2331,7 +2331,6 @@ C2V_VMENTRY_PREFIX(jlong, getCurrentJavaThread, (JNIEnv* env, jobject c2vm))
|
||||
// Called from unattached JVMCI shared library thread
|
||||
return 0L;
|
||||
}
|
||||
JVMCITraceMark jtm("getCurrentJavaThread");
|
||||
return (jlong) p2i(thread);
|
||||
C2V_END
|
||||
|
||||
@ -2377,10 +2376,10 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb
|
||||
attachSharedLibraryThread(env, name, as_daemon);
|
||||
return true;
|
||||
}
|
||||
JVMCITraceMark jtm("attachCurrentThread");
|
||||
if (thread->jni_environment() == env) {
|
||||
// Called from HotSpot
|
||||
C2V_BLOCK(jboolean, attachCurrentThread, (JNIEnv* env, jobject, jboolean))
|
||||
JVMCITraceMark jtm("attachCurrentThread");
|
||||
requireJVMCINativeLibrary(JVMCI_CHECK_0);
|
||||
|
||||
JVMCIRuntime* runtime = JVMCI::compiler_runtime(thread);
|
||||
@ -2435,10 +2434,10 @@ C2V_VMENTRY_PREFIX(jboolean, detachCurrentThread, (JNIEnv* env, jobject c2vm, jb
|
||||
// Called from unattached JVMCI shared library thread
|
||||
JNI_THROW_("detachCurrentThread", IllegalStateException, "Cannot detach non-attached thread", false);
|
||||
}
|
||||
JVMCITraceMark jtm("detachCurrentThread");
|
||||
if (thread->jni_environment() == env) {
|
||||
// Called from HotSpot
|
||||
C2V_BLOCK(void, detachCurrentThread, (JNIEnv* env, jobject))
|
||||
JVMCITraceMark jtm("detachCurrentThread");
|
||||
requireJVMCINativeLibrary(JVMCI_CHECK_0);
|
||||
requireInHotSpot("detachCurrentThread", JVMCI_CHECK_0);
|
||||
JVMCIRuntime* runtime = thread->libjvmci_runtime();
|
||||
|
@ -39,11 +39,15 @@
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/jniHandles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "jvmci/jniAccessMark.inline.hpp"
|
||||
#include "jvmci/jvmciCompiler.hpp"
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
|
||||
jbyte* JVMCIEnv::_serialized_saved_properties = nullptr;
|
||||
int JVMCIEnv::_serialized_saved_properties_len = 0;
|
||||
|
||||
JVMCICompileState::JVMCICompileState(CompileTask* task, JVMCICompiler* compiler):
|
||||
_task(task),
|
||||
_compiler(compiler),
|
||||
@ -98,61 +102,73 @@ bool JVMCICompileState::jvmti_state_changed() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void JVMCIEnv::copy_saved_properties() {
|
||||
assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image");
|
||||
jbyte* JVMCIEnv::get_serialized_saved_properties(int& props_len, TRAPS) {
|
||||
jbyte* props = _serialized_saved_properties;
|
||||
if (props == nullptr) {
|
||||
// load VMSupport
|
||||
Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport();
|
||||
Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK_NULL);
|
||||
|
||||
JavaThread* THREAD = JavaThread::current(); // For exception macros.
|
||||
|
||||
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_services_Services(), Handle(), Handle(), true, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
JVMCIRuntime::fatal_exception(NULL, "Error initializing jdk.vm.ci.services.Services");
|
||||
}
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
if (ik->should_be_initialized()) {
|
||||
ik->initialize(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
JVMCIRuntime::fatal_exception(NULL, "Error initializing jdk.vm.ci.services.Services");
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
if (ik->should_be_initialized()) {
|
||||
ik->initialize(CHECK_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the serialized saved properties from HotSpot
|
||||
TempNewSymbol serializeSavedProperties = SymbolTable::new_symbol("serializeSavedProperties");
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCallArguments args;
|
||||
JavaCalls::call_static(&result, ik, serializeSavedProperties, vmSymbols::void_byte_array_signature(), &args, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
JVMCIRuntime::fatal_exception(NULL, "Error calling jdk.vm.ci.services.Services.serializeSavedProperties");
|
||||
}
|
||||
oop res = result.get_oop();
|
||||
assert(res->is_typeArray(), "must be");
|
||||
assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "must be");
|
||||
typeArrayOop ba = typeArrayOop(res);
|
||||
int serialized_properties_len = ba->length();
|
||||
// invoke the serializeSavedPropertiesToByteArray method
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCallArguments args;
|
||||
|
||||
// Copy serialized saved properties from HotSpot object into native buffer
|
||||
jbyte* serialized_properties = NEW_RESOURCE_ARRAY(jbyte, serialized_properties_len);
|
||||
memcpy(serialized_properties, ba->byte_at_addr(0), serialized_properties_len);
|
||||
Symbol* signature = vmSymbols::void_byte_array_signature();
|
||||
JavaCalls::call_static(&result,
|
||||
ik,
|
||||
vmSymbols::serializeSavedPropertiesToByteArray_name(),
|
||||
signature,
|
||||
&args,
|
||||
CHECK_NULL);
|
||||
|
||||
oop res = result.get_oop();
|
||||
assert(res->is_typeArray(), "must be");
|
||||
assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "must be");
|
||||
typeArrayOop ba = typeArrayOop(res);
|
||||
props_len = ba->length();
|
||||
|
||||
// Copy serialized saved properties from HotSpot object into C heap
|
||||
props = NEW_C_HEAP_ARRAY(jbyte, props_len, mtJVMCI);
|
||||
memcpy(props, ba->byte_at_addr(0), props_len);
|
||||
|
||||
_serialized_saved_properties_len = props_len;
|
||||
_serialized_saved_properties = props;
|
||||
} else {
|
||||
props_len = _serialized_saved_properties_len;
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
void JVMCIEnv::copy_saved_properties(jbyte* properties, int properties_len, JVMCI_TRAPS) {
|
||||
assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image");
|
||||
JavaThread* thread = JavaThread::current(); // For exception macros.
|
||||
|
||||
// Copy native buffer into shared library object
|
||||
JVMCIPrimitiveArray buf = new_byteArray(serialized_properties_len, this);
|
||||
JVMCIPrimitiveArray buf = new_byteArray(properties_len, this);
|
||||
if (has_pending_exception()) {
|
||||
describe_pending_exception(true);
|
||||
fatal("Error in copy_saved_properties");
|
||||
_runtime->fatal_exception(JVMCIENV, "Error in copy_saved_properties");
|
||||
}
|
||||
copy_bytes_from(serialized_properties, buf, 0, serialized_properties_len);
|
||||
copy_bytes_from(properties, buf, 0, properties_len);
|
||||
if (has_pending_exception()) {
|
||||
describe_pending_exception(true);
|
||||
fatal("Error in copy_saved_properties");
|
||||
_runtime->fatal_exception(JVMCIENV, "Error in copy_saved_properties");
|
||||
}
|
||||
|
||||
// Initialize saved properties in shared library
|
||||
jclass servicesClass = JNIJVMCI::Services::clazz();
|
||||
jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method();
|
||||
JNIAccessMark jni(this, THREAD);
|
||||
jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject());
|
||||
if (jni()->ExceptionCheck()) {
|
||||
jni()->ExceptionDescribe();
|
||||
fatal("Error calling jdk.vm.ci.services.Services.initializeSavedProperties");
|
||||
bool exception = false;
|
||||
{
|
||||
JNIAccessMark jni(this, thread);
|
||||
jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject());
|
||||
exception = jni()->ExceptionCheck();
|
||||
}
|
||||
if (exception) {
|
||||
_runtime->fatal_exception(JVMCIENV, "Error calling jdk.vm.ci.services.Services.initializeSavedProperties");
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,39 +318,40 @@ class ExceptionTranslation: public StackObj {
|
||||
// Encodes the exception in `_from_env` into `buffer`.
|
||||
// Where N is the number of bytes needed for the encoding, returns N if N <= `buffer_size`
|
||||
// and the encoding was written to `buffer` otherwise returns -N.
|
||||
virtual int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) = 0;
|
||||
virtual int encode(JavaThread* THREAD, Klass* vmSupport, jlong buffer, int buffer_size) = 0;
|
||||
|
||||
// Decodes the exception in `buffer` in `_to_env` and throws it.
|
||||
virtual void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) = 0;
|
||||
virtual void decode(JavaThread* THREAD, Klass* vmSupport, jlong buffer) = 0;
|
||||
|
||||
public:
|
||||
void doit(JavaThread* THREAD) {
|
||||
// Resolve HotSpotJVMCIRuntime class explicitly as HotSpotJVMCI::compute_offsets
|
||||
// Resolve VMSupport class explicitly as HotSpotJVMCI::compute_offsets
|
||||
// may not have been called.
|
||||
Klass* runtimeKlass = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_hotspot_HotSpotJVMCIRuntime(), true, CHECK);
|
||||
Klass* vmSupport = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_VMSupport(), true, THREAD);
|
||||
guarantee(!HAS_PENDING_EXCEPTION, "");
|
||||
|
||||
int buffer_size = 2048;
|
||||
while (true) {
|
||||
ResourceMark rm;
|
||||
jlong buffer = (jlong) NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jbyte, buffer_size);
|
||||
if (buffer == 0L) {
|
||||
decode(THREAD, runtimeKlass, 0L);
|
||||
decode(THREAD, vmSupport, 0L);
|
||||
return;
|
||||
}
|
||||
int res = encode(THREAD, runtimeKlass, buffer, buffer_size);
|
||||
int res = encode(THREAD, vmSupport, buffer, buffer_size);
|
||||
if (_from_env != nullptr && !_from_env->is_hotspot() && _from_env->has_pending_exception()) {
|
||||
// Cannot get name of exception thrown by `encode` as that involves
|
||||
// calling into libjvmci which in turn can raise another exception.
|
||||
_from_env->clear_pending_exception();
|
||||
decode(THREAD, runtimeKlass, -2L);
|
||||
decode(THREAD, vmSupport, -2L);
|
||||
return;
|
||||
} else if (HAS_PENDING_EXCEPTION) {
|
||||
Symbol *ex_name = PENDING_EXCEPTION->klass()->name();
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
|
||||
decode(THREAD, runtimeKlass, -1L);
|
||||
decode(THREAD, vmSupport, -1L);
|
||||
} else {
|
||||
decode(THREAD, runtimeKlass, -2L);
|
||||
decode(THREAD, vmSupport, -2L);
|
||||
}
|
||||
return;
|
||||
} else if (res < 0) {
|
||||
@ -343,9 +360,9 @@ class ExceptionTranslation: public StackObj {
|
||||
buffer_size = required_buffer_size;
|
||||
}
|
||||
} else {
|
||||
decode(THREAD, runtimeKlass, buffer);
|
||||
decode(THREAD, vmSupport, buffer);
|
||||
if (!_to_env->has_pending_exception()) {
|
||||
_to_env->throw_InternalError("HotSpotJVMCIRuntime.decodeAndThrowThrowable should have thrown an exception");
|
||||
_to_env->throw_InternalError("decodeAndThrowThrowable should have thrown an exception");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -358,23 +375,23 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
|
||||
private:
|
||||
const Handle& _throwable;
|
||||
|
||||
int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) {
|
||||
int encode(JavaThread* THREAD, Klass* vmSupport, jlong buffer, int buffer_size) {
|
||||
JavaCallArguments jargs;
|
||||
jargs.push_oop(_throwable);
|
||||
jargs.push_long(buffer);
|
||||
jargs.push_int(buffer_size);
|
||||
JavaValue result(T_INT);
|
||||
JavaCalls::call_static(&result,
|
||||
runtimeKlass,
|
||||
vmSupport,
|
||||
vmSymbols::encodeThrowable_name(),
|
||||
vmSymbols::encodeThrowable_signature(), &jargs, THREAD);
|
||||
return result.get_jint();
|
||||
}
|
||||
|
||||
void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) {
|
||||
void decode(JavaThread* THREAD, Klass* vmSupport, jlong buffer) {
|
||||
JNIAccessMark jni(_to_env, THREAD);
|
||||
jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
|
||||
JNIJVMCI::HotSpotJVMCIRuntime::decodeAndThrowThrowable_method(),
|
||||
jni()->CallStaticVoidMethod(JNIJVMCI::VMSupport::clazz(),
|
||||
JNIJVMCI::VMSupport::decodeAndThrowThrowable_method(),
|
||||
buffer);
|
||||
}
|
||||
public:
|
||||
@ -387,19 +404,19 @@ class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation {
|
||||
private:
|
||||
jthrowable _throwable;
|
||||
|
||||
int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) {
|
||||
int encode(JavaThread* THREAD, Klass* vmSupport, jlong buffer, int buffer_size) {
|
||||
JNIAccessMark jni(_from_env, THREAD);
|
||||
return jni()->CallStaticIntMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
|
||||
JNIJVMCI::HotSpotJVMCIRuntime::encodeThrowable_method(),
|
||||
return jni()->CallStaticIntMethod(JNIJVMCI::VMSupport::clazz(),
|
||||
JNIJVMCI::VMSupport::encodeThrowable_method(),
|
||||
_throwable, buffer, buffer_size);
|
||||
}
|
||||
|
||||
void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) {
|
||||
void decode(JavaThread* THREAD, Klass* vmSupport, jlong buffer) {
|
||||
JavaCallArguments jargs;
|
||||
jargs.push_long(buffer);
|
||||
JavaValue result(T_VOID);
|
||||
JavaCalls::call_static(&result,
|
||||
runtimeKlass,
|
||||
vmSupport,
|
||||
vmSymbols::decodeAndThrowThrowable_name(),
|
||||
vmSymbols::long_void_signature(), &jargs, THREAD);
|
||||
}
|
||||
@ -416,31 +433,34 @@ void JVMCIEnv::translate_from_jni_exception(JavaThread* THREAD, jthrowable throw
|
||||
SharedLibraryToHotSpotExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD);
|
||||
}
|
||||
|
||||
jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env) {
|
||||
if (is_hotspot()) {
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
translate_to_jni_exception(THREAD, throwable, this, peer_env);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
jthrowable ex = nullptr;
|
||||
{
|
||||
JNIAccessMark jni(this, THREAD);
|
||||
ex = jni()->ExceptionOccurred();
|
||||
if (ex != nullptr) {
|
||||
jni()->ExceptionClear();
|
||||
}
|
||||
}
|
||||
if (ex != nullptr) {
|
||||
translate_from_jni_exception(THREAD, ex, peer_env, this);
|
||||
return true;
|
||||
}
|
||||
jboolean JVMCIEnv::transfer_pending_exception_to_jni(JavaThread* THREAD, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) {
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
translate_to_jni_exception(THREAD, throwable, hotspot_env, jni_env);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env) {
|
||||
if (is_hotspot()) {
|
||||
return transfer_pending_exception_to_jni(THREAD, this, peer_env);
|
||||
}
|
||||
jthrowable ex = nullptr;
|
||||
{
|
||||
JNIAccessMark jni(this, THREAD);
|
||||
ex = jni()->ExceptionOccurred();
|
||||
if (ex != nullptr) {
|
||||
jni()->ExceptionClear();
|
||||
}
|
||||
}
|
||||
if (ex != nullptr) {
|
||||
translate_from_jni_exception(THREAD, ex, peer_env, this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JVMCIEnv::~JVMCIEnv() {
|
||||
if (_attach_threw_OOME) {
|
||||
@ -469,7 +489,8 @@ JVMCIEnv::~JVMCIEnv() {
|
||||
|
||||
if (has_pending_exception()) {
|
||||
char message[256];
|
||||
jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line);
|
||||
jio_snprintf(message, 256, "Uncaught exception exiting %s JVMCIEnv scope entered at %s:%d",
|
||||
is_hotspot() ? "HotSpot" : "libjvmci", _file, _line);
|
||||
JVMCIRuntime::fatal_exception(this, message);
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,12 @@ class JVMCIEnv : public ResourceObj {
|
||||
// The translated exception is pending in hotspot_env upon returning.
|
||||
static void translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env);
|
||||
|
||||
// Used by copy_saved_properties() to avoid OutOfMemoryErrors when
|
||||
// initializing a libjvmci runtime in low HotSpot heap conditions.
|
||||
// Must hold JVMCI_lock when initializing.
|
||||
static jbyte* _serialized_saved_properties;
|
||||
static int _serialized_saved_properties_len;
|
||||
|
||||
public:
|
||||
// Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM).
|
||||
// An exception occurring within the scope is left pending when the
|
||||
@ -221,9 +227,13 @@ public:
|
||||
return _runtime;
|
||||
}
|
||||
|
||||
// Initializes Services.savedProperties in the shared library by copying
|
||||
// the values from the same field in the HotSpot heap.
|
||||
void copy_saved_properties();
|
||||
// Gets the serialized saved properties from the HotSpot heap.
|
||||
// The length of the returned array is saved in `len`.
|
||||
jbyte* get_serialized_saved_properties(int& len, TRAPS);
|
||||
|
||||
// Initializes Services.savedProperties in the shared library from the given
|
||||
// properties in the format produced by `get_serialized_saved_properties`.
|
||||
void copy_saved_properties(jbyte* properties, int properties_len, JVMCI_TRAPS);
|
||||
|
||||
jboolean has_pending_exception();
|
||||
void clear_pending_exception();
|
||||
@ -233,6 +243,11 @@ public:
|
||||
// if a pending exception was transferred, false otherwise.
|
||||
jboolean transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env);
|
||||
|
||||
// If there is a pending HotSpot exception, clears it and translates it to the shared library heap.
|
||||
// The translated exception is pending in the shared library upon returning.
|
||||
// Returns true if a pending exception was transferred, false otherwise.
|
||||
static jboolean transfer_pending_exception_to_jni(JavaThread* THREAD, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env);
|
||||
|
||||
// Prints an exception and stack trace of a pending exception.
|
||||
void describe_pending_exception(bool clear);
|
||||
|
||||
|
@ -346,7 +346,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz,
|
||||
JVMCI_event_2(" jclass for %s = " PTR_FORMAT, current_class_name, p2i(k)); \
|
||||
/* SVM guarantees that jclass handles to classes in a native image are also */ \
|
||||
/* in the image. Further calling NewGlobalRef on such a handle returns a stable */ \
|
||||
/* values across all JavaVMs executing on the same native image. */ \
|
||||
/* value across all JavaVMs executing on the same native image. */ \
|
||||
if (current != nullptr) { \
|
||||
fatal("jclass for %s re-initialized: " PTR_FORMAT " -> " PTR_FORMAT, \
|
||||
current_class_name, p2i(current), p2i(k)); \
|
||||
|
@ -191,8 +191,6 @@
|
||||
objectarray_field(HotSpotJVMCIRuntime, excludeFromJVMCICompilation, "[Ljava/lang/Module;") \
|
||||
jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature, (JVMCIObject runtime, JVMCIObject method, int entry_bci, jlong env, int id)) \
|
||||
jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, isGCSupported, int_bool_signature, (JVMCIObject runtime, int gcIdentifier)) \
|
||||
jvmci_method(CallStaticBooleanMethod, GetStaticMethodID, call_static, bool, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable, jlong buffer, int buffer_size)) \
|
||||
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, decodeAndThrowThrowable, long_void_signature, (jlong buffer)) \
|
||||
jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \
|
||||
jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \
|
||||
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, runtime, runtime_signature, (JVMCI_TRAPS)) \
|
||||
@ -216,6 +214,10 @@
|
||||
start_class(Class, java_lang_Class) \
|
||||
jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, Class, getName, void_string_signature, (JVMCI_TRAPS)) \
|
||||
end_class \
|
||||
start_class(VMSupport, jdk_internal_vm_VMSupport) \
|
||||
jvmci_method(CallStaticIntMethod, GetStaticMethodID, call_static, int, VMSupport, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable, jlong buffer, int buffer_size)) \
|
||||
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, VMSupport, decodeAndThrowThrowable, long_void_signature, (jlong buffer)) \
|
||||
end_class \
|
||||
start_class(ArrayIndexOutOfBoundsException, java_lang_ArrayIndexOutOfBoundsException) \
|
||||
jvmci_constructor(ArrayIndexOutOfBoundsException, "(Ljava/lang/String;)V") \
|
||||
end_class \
|
||||
|
@ -749,7 +749,7 @@ JVM_END
|
||||
void JVMCIRuntime::call_getCompiler(TRAPS) {
|
||||
THREAD_JVMCIENV(JavaThread::current());
|
||||
JVMCIObject jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_CHECK);
|
||||
initialize(JVMCIENV);
|
||||
initialize(JVMCI_CHECK);
|
||||
JVMCIENV->call_HotSpotJVMCIRuntime_getCompiler(jvmciRuntime, JVMCI_CHECK);
|
||||
}
|
||||
|
||||
@ -1315,7 +1315,7 @@ void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
initialize(JVMCIENV);
|
||||
initialize(JVMCI_CHECK);
|
||||
|
||||
// This should only be called in the context of the JVMCI class being initialized
|
||||
JVMCIObject result = JVMCIENV->call_HotSpotJVMCIRuntime_runtime(JVMCI_CHECK);
|
||||
@ -1370,12 +1370,17 @@ class JavaVMRefsInitialization: public StackObj {
|
||||
}
|
||||
};
|
||||
|
||||
void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
|
||||
void JVMCIRuntime::initialize(JVMCI_TRAPS) {
|
||||
// Check first without _lock
|
||||
if (_init_state == fully_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
JavaThread* THREAD = JavaThread::current();
|
||||
|
||||
int properties_len = 0;
|
||||
jbyte* properties = NULL;
|
||||
|
||||
MutexLocker locker(_lock);
|
||||
// Check again under _lock
|
||||
if (_init_state == fully_initialized) {
|
||||
@ -1397,7 +1402,6 @@ void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
|
||||
{
|
||||
MutexUnlocker unlock(_lock);
|
||||
|
||||
JavaThread* THREAD = JavaThread::current();
|
||||
HandleMark hm(THREAD);
|
||||
ResourceMark rm(THREAD);
|
||||
{
|
||||
@ -1441,7 +1445,12 @@ void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) {
|
||||
DEBUG_ONLY(CodeInstaller::verify_bci_constants(JVMCIENV);)
|
||||
|
||||
if (!JVMCIENV->is_hotspot()) {
|
||||
JVMCIENV->copy_saved_properties();
|
||||
Handle properties_exception;
|
||||
properties = JVMCIENV->get_serialized_saved_properties(properties_len, THREAD);
|
||||
if (JVMCIEnv::transfer_pending_exception_to_jni(THREAD, nullptr, JVMCIENV)) {
|
||||
return;
|
||||
}
|
||||
JVMCIENV->copy_saved_properties(properties, properties_len, JVMCI_CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1484,7 +1493,7 @@ void JVMCIRuntime::initialize_JVMCI(JVMCI_TRAPS) {
|
||||
}
|
||||
|
||||
JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
|
||||
initialize(JVMCIENV);
|
||||
initialize(JVMCI_CHECK_(JVMCIObject()));
|
||||
initialize_JVMCI(JVMCI_CHECK_(JVMCIObject()));
|
||||
return _HotSpotJVMCIRuntime_instance;
|
||||
}
|
||||
@ -1992,11 +2001,21 @@ void JVMCIRuntime::compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, c
|
||||
HandleMark hm(thread);
|
||||
JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV);
|
||||
if (JVMCIENV->has_pending_exception()) {
|
||||
fatal_exception(JVMCIENV, "Exception during HotSpotJVMCIRuntime initialization");
|
||||
if (PrintWarnings) {
|
||||
ResourceMark rm(thread);
|
||||
warning("HotSpotJVMCIRuntime initialization failed when compiling %s", method->name_and_sig_as_C_string());
|
||||
JVMCIENV->describe_pending_exception(true);
|
||||
}
|
||||
compile_state->set_failure(false, "exception during HotSpotJVMCIRuntime initialization");
|
||||
return;
|
||||
}
|
||||
JVMCIObject jvmci_method = JVMCIENV->get_jvmci_method(method, JVMCIENV);
|
||||
if (JVMCIENV->has_pending_exception()) {
|
||||
JVMCIENV->describe_pending_exception(true);
|
||||
if (PrintWarnings) {
|
||||
ResourceMark rm(thread);
|
||||
warning("Error creating JVMCI wrapper for %s", method->name_and_sig_as_C_string());
|
||||
JVMCIENV->describe_pending_exception(true);
|
||||
}
|
||||
compile_state->set_failure(false, "exception getting JVMCI wrapper method");
|
||||
return;
|
||||
}
|
||||
|
@ -79,9 +79,6 @@
|
||||
template(compileMethod_name, "compileMethod") \
|
||||
template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)Ljdk/vm/ci/hotspot/HotSpotCompilationRequestResult;") \
|
||||
template(isGCSupported_name, "isGCSupported") \
|
||||
template(encodeThrowable_name, "encodeThrowable") \
|
||||
template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \
|
||||
template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \
|
||||
template(fromMetaspace_name, "fromMetaspace") \
|
||||
template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \
|
||||
template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \
|
||||
|
@ -1954,8 +1954,10 @@ bool Arguments::check_vm_args_consistency() {
|
||||
if (status && EnableJVMCI) {
|
||||
PropertyList_unique_add(&_system_properties, "jdk.internal.vm.ci.enabled", "true",
|
||||
AddProperty, UnwriteableProperty, InternalProperty);
|
||||
if (!create_numbered_module_property("jdk.module.addmods", "jdk.internal.vm.ci", addmods_count++)) {
|
||||
return false;
|
||||
if (ClassLoader::is_module_observable("jdk.internal.vm.ci")) {
|
||||
if (!create_numbered_module_property("jdk.module.addmods", "jdk.internal.vm.ci", addmods_count++)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -4,7 +4,9 @@
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
@ -20,13 +22,14 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.hotspot;
|
||||
package jdk.internal.vm;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -35,31 +38,32 @@ import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import jdk.vm.ci.common.JVMCIError;
|
||||
|
||||
/**
|
||||
* Support for translating exceptions between different runtime heaps.
|
||||
* Support for translating exceptions between the HotSpot heap and libjvmci heap.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
final class TranslatedException extends Exception {
|
||||
|
||||
/**
|
||||
* The value returned by {@link #encodeThrowable(Throwable)} when encoding fails due to an
|
||||
* {@link OutOfMemoryError}.
|
||||
* The value returned by {@link #encodeThrowable(Throwable)} when encoding
|
||||
* fails due to an {@link OutOfMemoryError}.
|
||||
*/
|
||||
private static final byte[] FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES;
|
||||
|
||||
/**
|
||||
* The value returned by {@link #encodeThrowable(Throwable)} when encoding fails for any reason
|
||||
* other than {@link OutOfMemoryError}.
|
||||
* The value returned by {@link #encodeThrowable(Throwable)} when encoding
|
||||
* fails for any reason other than {@link OutOfMemoryError}.
|
||||
*/
|
||||
private static final byte[] FALLBACK_ENCODED_THROWABLE_BYTES;
|
||||
static {
|
||||
try {
|
||||
FALLBACK_ENCODED_THROWABLE_BYTES = encodeThrowable(new TranslatedException("error during encoding", "<unknown>"), false);
|
||||
FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES = encodeThrowable(new OutOfMemoryError(), false);
|
||||
FALLBACK_ENCODED_THROWABLE_BYTES =
|
||||
encodeThrowable(new TranslatedException("error during encoding",
|
||||
"<unknown>"), false);
|
||||
FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES =
|
||||
encodeThrowable(new OutOfMemoryError(), false);
|
||||
} catch (IOException e) {
|
||||
throw new JVMCIError(e);
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +78,8 @@ final class TranslatedException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* No need to record an initial stack trace since it will be manually overwritten.
|
||||
* No need to record an initial stack trace since
|
||||
* it will be manually overwritten.
|
||||
*/
|
||||
@SuppressWarnings("sync-override")
|
||||
@Override
|
||||
@ -95,12 +100,14 @@ final class TranslatedException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a stack trace for {@code throwable} and returns {@code true}. Used to print stack
|
||||
* traces only when assertions are enabled.
|
||||
* Prints a stack trace for {@code throwable} if the system property
|
||||
* {@code "jdk.internal.vm.TranslatedException.debug"} is true.
|
||||
*/
|
||||
private static boolean printStackTrace(Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
return true;
|
||||
private static void debugPrintStackTrace(Throwable throwable) {
|
||||
if (Boolean.getBoolean("jdk.internal.vm.TranslatedException.debug")) {
|
||||
System.err.print("DEBUG: ");
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static Throwable initCause(Throwable throwable, Throwable cause) {
|
||||
@ -109,7 +116,7 @@ final class TranslatedException extends Exception {
|
||||
throwable.initCause(cause);
|
||||
} catch (IllegalStateException e) {
|
||||
// Cause could not be set or overwritten.
|
||||
assert printStackTrace(e);
|
||||
debugPrintStackTrace(e);
|
||||
}
|
||||
}
|
||||
return throwable;
|
||||
@ -120,7 +127,8 @@ final class TranslatedException extends Exception {
|
||||
try {
|
||||
Class<?> cls = Class.forName(className);
|
||||
if (cause != null) {
|
||||
// Handle known exception types whose cause must be set in the constructor
|
||||
// Handle known exception types whose cause must
|
||||
// be set in the constructor
|
||||
if (cls == InvocationTargetException.class) {
|
||||
return new InvocationTargetException(cause, message);
|
||||
}
|
||||
@ -129,10 +137,13 @@ final class TranslatedException extends Exception {
|
||||
}
|
||||
}
|
||||
if (message == null) {
|
||||
return initCause((Throwable) cls.getConstructor().newInstance(), cause);
|
||||
Constructor<?> cons = cls.getConstructor();
|
||||
return initCause((Throwable) cons.newInstance(), cause);
|
||||
}
|
||||
return initCause((Throwable) cls.getDeclaredConstructor(String.class).newInstance(message), cause);
|
||||
Constructor<?> cons = cls.getDeclaredConstructor(String.class);
|
||||
return initCause((Throwable) cons.newInstance(message), cause);
|
||||
} catch (Throwable translationFailure) {
|
||||
debugPrintStackTrace(translationFailure);
|
||||
return initCause(new TranslatedException(message, className), cause);
|
||||
}
|
||||
}
|
||||
@ -149,7 +160,7 @@ final class TranslatedException extends Exception {
|
||||
* Encodes {@code throwable} including its stack and causes as a {@linkplain GZIPOutputStream
|
||||
* compressed} byte array that can be decoded by {@link #decodeThrowable}.
|
||||
*/
|
||||
static byte[] encodeThrowable(Throwable throwable) throws Throwable {
|
||||
static byte[] encodeThrowable(Throwable throwable) {
|
||||
try {
|
||||
return encodeThrowable(throwable, true);
|
||||
} catch (OutOfMemoryError e) {
|
||||
@ -159,7 +170,8 @@ final class TranslatedException extends Exception {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] encodeThrowable(Throwable throwable, boolean withCauseAndStack) throws IOException {
|
||||
private static byte[] encodeThrowable(Throwable throwable,
|
||||
boolean withCauseAndStack) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(baos))) {
|
||||
List<Throwable> throwables = new ArrayList<>();
|
||||
@ -199,20 +211,20 @@ final class TranslatedException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stack of the current thread without the frames between this call and the one just
|
||||
* below the frame of the first method in {@link CompilerToVM}. The chopped frames are for the
|
||||
* VM call to {@link HotSpotJVMCIRuntime#decodeAndThrowThrowable}.
|
||||
* Gets the stack of the current thread as of the first native method. The chopped
|
||||
* frames are for the VM call to {@link VMSupport#decodeAndThrowThrowable}.
|
||||
*/
|
||||
private static StackTraceElement[] getMyStackTrace() {
|
||||
StackTraceElement[] stack = new Exception().getStackTrace();
|
||||
Exception ex = new Exception();
|
||||
StackTraceElement[] stack = ex.getStackTrace();
|
||||
for (int i = 0; i < stack.length; i++) {
|
||||
StackTraceElement e = stack[i];
|
||||
if (e.getClassName().equals(CompilerToVM.class.getName())) {
|
||||
if (e.isNativeMethod()) {
|
||||
return Arrays.copyOfRange(stack, i, stack.length);
|
||||
}
|
||||
}
|
||||
// This should never happen but since we're in exception handling
|
||||
// code, just return a safe value instead raising a nested exception.
|
||||
// This should never happen but since this is exception handling
|
||||
// code, be defensive instead raising a nested exception.
|
||||
return new StackTraceElement[0];
|
||||
}
|
||||
|
||||
@ -223,7 +235,8 @@ final class TranslatedException extends Exception {
|
||||
* {@link #encodeThrowable}
|
||||
*/
|
||||
static Throwable decodeThrowable(byte[] encodedThrowable) {
|
||||
try (DataInputStream dis = new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(encodedThrowable)))) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(encodedThrowable);
|
||||
try (DataInputStream dis = new DataInputStream(new GZIPInputStream(bais))) {
|
||||
Throwable cause = null;
|
||||
Throwable throwable = null;
|
||||
StackTraceElement[] myStack = getMyStackTrace();
|
||||
@ -243,7 +256,13 @@ final class TranslatedException extends Exception {
|
||||
String methodName = emptyAsNull(dis.readUTF());
|
||||
String fileName = emptyAsNull(dis.readUTF());
|
||||
int lineNumber = dis.readInt();
|
||||
StackTraceElement ste = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber);
|
||||
StackTraceElement ste = new StackTraceElement(classLoaderName,
|
||||
moduleName,
|
||||
moduleVersion,
|
||||
className,
|
||||
methodName,
|
||||
fileName,
|
||||
lineNumber);
|
||||
|
||||
if (ste.isNativeMethod()) {
|
||||
// Best effort attempt to weave stack traces from two heaps into
|
||||
@ -263,13 +282,18 @@ final class TranslatedException extends Exception {
|
||||
while (myStackIndex < myStack.length) {
|
||||
stackTrace[stackTraceIndex++] = myStack[myStackIndex++];
|
||||
}
|
||||
if (stackTraceIndex != stackTrace.length) {
|
||||
// Remove null entries at end of stackTrace
|
||||
stackTrace = Arrays.copyOf(stackTrace, stackTraceIndex);
|
||||
}
|
||||
throwable.setStackTrace(stackTrace);
|
||||
cause = throwable;
|
||||
}
|
||||
return throwable;
|
||||
} catch (Throwable translationFailure) {
|
||||
assert printStackTrace(translationFailure);
|
||||
return new TranslatedException("Error decoding exception: " + encodedThrowable, translationFailure.getClass().getName());
|
||||
debugPrintStackTrace(translationFailure);
|
||||
return new TranslatedException("Error decoding exception: " + encodedThrowable,
|
||||
translationFailure.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,12 +32,17 @@ import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.jar.Attributes;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/*
|
||||
* Support class used by JVMTI and VM attach mechanism.
|
||||
* Support class used by JVMCI, JVMTI and VM attach mechanism.
|
||||
*/
|
||||
public class VMSupport {
|
||||
|
||||
private static final Unsafe U = Unsafe.getUnsafe();
|
||||
private static Properties agentProps = null;
|
||||
|
||||
/**
|
||||
* Returns the agent properties.
|
||||
*/
|
||||
@ -51,13 +56,20 @@ public class VMSupport {
|
||||
private static native Properties initAgentProperties(Properties props);
|
||||
|
||||
/**
|
||||
* Write the given properties list to a byte array and return it. Properties with
|
||||
* a key or value that is not a String is filtered out. The stream written to the byte
|
||||
* array is ISO 8859-1 encoded.
|
||||
* Writes the given properties list to a byte array and return it. The stream written
|
||||
* to the byte array is ISO 8859-1 encoded.
|
||||
*/
|
||||
private static byte[] serializePropertiesToByteArray(Properties p) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
|
||||
p.store(out, null);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns a Properties object containing only the entries in {@code p}
|
||||
* whose key and value are both Strings
|
||||
*/
|
||||
private static Properties onlyStrings(Properties p) {
|
||||
Properties props = new Properties();
|
||||
|
||||
// stringPropertyNames() returns a snapshot of the property keys
|
||||
@ -66,17 +78,28 @@ public class VMSupport {
|
||||
String value = p.getProperty(key);
|
||||
props.put(key, value);
|
||||
}
|
||||
|
||||
props.store(out, null);
|
||||
return out.toByteArray();
|
||||
return props;
|
||||
}
|
||||
|
||||
public static byte[] serializePropertiesToByteArray() throws IOException {
|
||||
return serializePropertiesToByteArray(System.getProperties());
|
||||
return serializePropertiesToByteArray(onlyStrings(System.getProperties()));
|
||||
}
|
||||
|
||||
public static byte[] serializeAgentPropertiesToByteArray() throws IOException {
|
||||
return serializePropertiesToByteArray(getAgentProperties());
|
||||
return serializePropertiesToByteArray(onlyStrings(getAgentProperties()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes {@link VM#getSavedProperties()} to a byte array.
|
||||
*
|
||||
* Used by JVMCI to copy properties into libjvmci.
|
||||
*/
|
||||
public static byte[] serializeSavedPropertiesToByteArray() throws IOException {
|
||||
Properties props = new Properties();
|
||||
for (var e : VM.getSavedProperties().entrySet()) {
|
||||
props.put(e.getKey(), e.getValue());
|
||||
}
|
||||
return serializePropertiesToByteArray(props);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -88,4 +111,40 @@ public class VMSupport {
|
||||
* variables such as java.io.tmpdir.
|
||||
*/
|
||||
public static native String getVMTemporaryDirectory();
|
||||
|
||||
/**
|
||||
* Decodes the exception encoded in {@code buffer} and throws it.
|
||||
*
|
||||
* @param buffer a native byte buffer containing an exception encoded by
|
||||
* {@link #encodeThrowable}
|
||||
*/
|
||||
public static void decodeAndThrowThrowable(long buffer) throws Throwable {
|
||||
int encodingLength = U.getInt(buffer);
|
||||
byte[] encoding = new byte[encodingLength];
|
||||
U.copyMemory(null, buffer + 4, encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, encodingLength);
|
||||
throw TranslatedException.decodeThrowable(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code bufferSize} is large enough, encodes {@code throwable} into a byte array and writes
|
||||
* it to {@code buffer}. The encoding in {@code buffer} can be decoded by
|
||||
* {@link #decodeAndThrowThrowable}.
|
||||
*
|
||||
* @param throwable the exception to encode
|
||||
* @param buffer a native byte buffer
|
||||
* @param bufferSize the size of {@code buffer} in bytes
|
||||
* @return the number of bytes written into {@code buffer} if {@code bufferSize} is large
|
||||
* enough, otherwise {@code -N} where {@code N} is the value {@code bufferSize} needs to
|
||||
* be to fit the encoding
|
||||
*/
|
||||
public static int encodeThrowable(Throwable throwable, long buffer, int bufferSize) {
|
||||
byte[] encoding = TranslatedException.encodeThrowable(throwable);
|
||||
int requiredSize = 4 + encoding.length;
|
||||
if (bufferSize < requiredSize) {
|
||||
return -requiredSize;
|
||||
}
|
||||
U.putInt(buffer, encoding.length);
|
||||
U.copyMemory(encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, buffer + 4, encoding.length);
|
||||
return requiredSize;
|
||||
}
|
||||
}
|
||||
|
@ -206,64 +206,6 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the exception encoded in {@code buffer} and throws it.
|
||||
*
|
||||
* @param errorOrBuffer an error code or a native byte buffer containing an exception encoded by
|
||||
* {@link #encodeThrowable}. Error code values and their meanings are:
|
||||
*
|
||||
* <pre>
|
||||
* 0: native memory for the buffer could not be allocated
|
||||
* -1: an OutOfMemoryError was thrown while encoding the exception
|
||||
* -2: some other throwable was thrown while encoding the exception
|
||||
* </pre>
|
||||
*/
|
||||
@VMEntryPoint
|
||||
static void decodeAndThrowThrowable(long errorOrBuffer) throws Throwable {
|
||||
if (errorOrBuffer >= -2L && errorOrBuffer <= 0) {
|
||||
String context = String.format("while encoding an exception to translate it from %s to %s",
|
||||
IS_IN_NATIVE_IMAGE ? "HotSpot" : "libjvmci",
|
||||
IS_IN_NATIVE_IMAGE ? "libjvmci" : "HotSpot");
|
||||
if (errorOrBuffer == 0) {
|
||||
throw new InternalError("native buffer could not be allocated " + context);
|
||||
}
|
||||
if (errorOrBuffer == -1L) {
|
||||
throw new OutOfMemoryError("OutOfMemoryError occurred " + context);
|
||||
}
|
||||
throw new InternalError("unexpected problem occurred " + context);
|
||||
}
|
||||
Unsafe unsafe = UnsafeAccess.UNSAFE;
|
||||
int encodingLength = unsafe.getInt(errorOrBuffer);
|
||||
byte[] encoding = new byte[encodingLength];
|
||||
unsafe.copyMemory(null, errorOrBuffer + 4, encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, encodingLength);
|
||||
throw TranslatedException.decodeThrowable(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code bufferSize} is large enough, encodes {@code throwable} into a byte array and writes
|
||||
* it to {@code buffer}. The encoding in {@code buffer} can be decoded by
|
||||
* {@link #decodeAndThrowThrowable}.
|
||||
*
|
||||
* @param throwable the exception to encode
|
||||
* @param buffer a native byte buffer
|
||||
* @param bufferSize the size of {@code buffer} in bytes
|
||||
* @return the number of bytes written into {@code buffer} if {@code bufferSize} is large
|
||||
* enough, otherwise {@code -N} where {@code N} is the value {@code bufferSize} needs to
|
||||
* be to fit the encoding
|
||||
*/
|
||||
@VMEntryPoint
|
||||
static int encodeThrowable(Throwable throwable, long buffer, int bufferSize) throws Throwable {
|
||||
byte[] encoding = TranslatedException.encodeThrowable(throwable);
|
||||
int requiredSize = 4 + encoding.length;
|
||||
if (bufferSize < requiredSize) {
|
||||
return -requiredSize;
|
||||
}
|
||||
Unsafe unsafe = UnsafeAccess.UNSAFE;
|
||||
unsafe.putInt(buffer, encoding.length);
|
||||
unsafe.copyMemory(encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, buffer + 4, encoding.length);
|
||||
return requiredSize;
|
||||
}
|
||||
|
||||
@VMEntryPoint
|
||||
static String callToString(Object o) {
|
||||
return o.toString();
|
||||
@ -1330,7 +1272,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
|
||||
for (String filter : filters) {
|
||||
Matcher m = FORCE_TRANSLATE_FAILURE_FILTER_RE.matcher(filter);
|
||||
if (!m.matches()) {
|
||||
throw new JVMCIError(Option.ForceTranslateFailure + " filter does not match " + FORCE_TRANSLATE_FAILURE_FILTER_RE + ": " + filter);
|
||||
throw new IllegalArgumentException(Option.ForceTranslateFailure + " filter does not match " + FORCE_TRANSLATE_FAILURE_FILTER_RE + ": " + filter);
|
||||
}
|
||||
String typeSelector = m.group(1);
|
||||
String substring = m.group(2);
|
||||
@ -1350,7 +1292,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
|
||||
continue;
|
||||
}
|
||||
if (toMatch.contains(substring)) {
|
||||
throw new JVMCIError("translation of " + translatedObject + " failed due to matching " + Option.ForceTranslateFailure + " filter \"" + filter + "\"");
|
||||
throw new RuntimeException("translation of " + translatedObject + " failed due to matching " + Option.ForceTranslateFailure + " filter \"" + filter + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,9 +23,6 @@
|
||||
package jdk.vm.ci.services;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -34,6 +31,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@ -42,8 +40,6 @@ import java.util.function.Supplier;
|
||||
import jdk.internal.misc.TerminatingThreadLocal;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Provides utilities needed by JVMCI clients.
|
||||
*/
|
||||
@ -266,109 +262,21 @@ public final class Services {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the purpose of {@linkplain #initializeSavedProperties(byte[]) initializing} the initial
|
||||
* properties in the JVMCI shared library.
|
||||
*/
|
||||
@VMEntryPoint
|
||||
private static byte[] serializeSavedProperties() throws IOException {
|
||||
if (IS_IN_NATIVE_IMAGE) {
|
||||
throw new InternalError("Can only serialize saved properties in HotSpot runtime");
|
||||
}
|
||||
return serializeProperties(Services.getSavedProperties());
|
||||
}
|
||||
|
||||
private static byte[] serializeProperties(Map<String, String> props) throws IOException {
|
||||
// Compute size of output on the assumption that
|
||||
// all system properties have ASCII names and values
|
||||
int estimate = 4 + 4;
|
||||
int nonUtf8Props = 0;
|
||||
for (Map.Entry<String, String> e : props.entrySet()) {
|
||||
String name = e.getKey();
|
||||
String value = e.getValue();
|
||||
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);
|
||||
DataOutputStream out = new DataOutputStream(baos);
|
||||
out.writeInt(props.size() - nonUtf8Props);
|
||||
out.writeInt(nonUtf8Props);
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialized the {@linkplain #getSavedProperties() saved system properties} in the JVMCI
|
||||
* shared library from the {@linkplain #serializeSavedProperties() serialized saved properties}
|
||||
* in the HotSpot runtime.
|
||||
* Initializes {@link #savedProperties} from the byte array returned by
|
||||
* {@code jdk.internal.vm.VMSupport.serializeSavedPropertiesToByteArray()}.
|
||||
*/
|
||||
@VMEntryPoint
|
||||
private static void initializeSavedProperties(byte[] serializedProperties) throws IOException {
|
||||
if (!IS_IN_NATIVE_IMAGE) {
|
||||
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));
|
||||
int utf8Props = in.readInt();
|
||||
int nonUtf8Props = in.readInt();
|
||||
Map<String, String> props = new HashMap<>(utf8Props + nonUtf8Props);
|
||||
int index = 0;
|
||||
while (in.available() != 0) {
|
||||
if (index < utf8Props) {
|
||||
String name = in.readUTF();
|
||||
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++;
|
||||
Properties props = new Properties();
|
||||
props.load(new ByteArrayInputStream(serializedProperties));
|
||||
Map<String, String> map = new HashMap<>(props.size());
|
||||
for (var e : props.entrySet()) {
|
||||
map.put((String) e.getKey(), (String) e.getValue());
|
||||
}
|
||||
return props;
|
||||
|
||||
savedProperties = Collections.unmodifiableMap(map);
|
||||
}
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @requires vm.jvmci
|
||||
* @modules jdk.internal.vm.ci/jdk.vm.ci.services:+open
|
||||
* @library /compiler/jvmci/jdk.vm.ci.hotspot.test/src
|
||||
* @run testng/othervm
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler
|
||||
* jdk.vm.ci.hotspot.test.TestServices
|
||||
*/
|
||||
|
||||
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.testng.Assert;
|
||||
import org.testng.annotations.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);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,16 +23,12 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @requires vm.jvmci
|
||||
* @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open
|
||||
* @modules java.base/jdk.internal.vm
|
||||
* java.base/jdk.internal.misc
|
||||
* @library /compiler/jvmci/jdk.vm.ci.hotspot.test/src
|
||||
* @run testng/othervm
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler
|
||||
* jdk.vm.ci.hotspot.test.TestTranslatedException
|
||||
* jdk.internal.vm.test.TestTranslatedException
|
||||
*/
|
||||
|
||||
package jdk.vm.ci.hotspot.test;
|
||||
package jdk.internal.vm.test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
@ -43,7 +39,7 @@ import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
|
||||
import jdk.internal.vm.VMSupport;
|
||||
|
||||
public class TestTranslatedException {
|
||||
@SuppressWarnings("serial")
|
||||
@ -56,52 +52,37 @@ public class TestTranslatedException {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void encodeDecodeTest() throws Exception {
|
||||
|
||||
Class<?> translatedExceptionClass = Class.forName("jdk.vm.ci.hotspot.TranslatedException");
|
||||
|
||||
Method encode = translatedExceptionClass.getDeclaredMethod("encodeThrowable", Throwable.class);
|
||||
Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", byte[].class);
|
||||
encode.setAccessible(true);
|
||||
decode.setAccessible(true);
|
||||
|
||||
Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke"));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
|
||||
}
|
||||
byte[] encoding = (byte[]) encode.invoke(null, throwable);
|
||||
Throwable decoded = (Throwable) decode.invoke(null, encoding);
|
||||
assertThrowableEquals(throwable, decoded);
|
||||
encodeDecode(throwable);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void encodeDecodeTest2() throws Exception {
|
||||
Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke"));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
|
||||
}
|
||||
encodeDecode(throwable);
|
||||
}
|
||||
|
||||
private void encodeDecode(Throwable throwable) throws Exception {
|
||||
Unsafe unsafe = Unsafe.getUnsafe();
|
||||
int bufferSize = 512;
|
||||
long buffer = 0L;
|
||||
while (true) {
|
||||
buffer = unsafe.allocateMemory(bufferSize);
|
||||
try {
|
||||
Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke"));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
|
||||
}
|
||||
|
||||
Method encode = HotSpotJVMCIRuntime.class.getDeclaredMethod("encodeThrowable", Throwable.class, long.class, int.class);
|
||||
Method decode = HotSpotJVMCIRuntime.class.getDeclaredMethod("decodeAndThrowThrowable", long.class);
|
||||
encode.setAccessible(true);
|
||||
decode.setAccessible(true);
|
||||
|
||||
int res = (Integer) encode.invoke(null, throwable, buffer, bufferSize);
|
||||
|
||||
int res = VMSupport.encodeThrowable(throwable, buffer, bufferSize);
|
||||
if (res < 0) {
|
||||
bufferSize = -res;
|
||||
} else {
|
||||
try {
|
||||
decode.invoke(null, buffer);
|
||||
VMSupport.decodeAndThrowThrowable(buffer);
|
||||
throw new AssertionError("expected decodeAndThrowThrowable to throw an exception");
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable decoded = e.getCause();
|
||||
} catch (Throwable decoded) {
|
||||
assertThrowableEquals(throwable, decoded);
|
||||
}
|
||||
return;
|
||||
@ -117,12 +98,12 @@ public class TestTranslatedException {
|
||||
Assert.assertEquals(original == null, decoded == null);
|
||||
while (original != null) {
|
||||
if (Untranslatable.class.equals(original.getClass())) {
|
||||
Assert.assertEquals("jdk.vm.ci.hotspot.TranslatedException", decoded.getClass().getName());
|
||||
Assert.assertEquals("jdk.vm.ci.hotspot.TranslatedException[jdk.vm.ci.hotspot.test.TestTranslatedException$Untranslatable]: test exception", decoded.toString());
|
||||
Assert.assertEquals("test exception", original.getMessage());
|
||||
Assert.assertEquals(decoded.getClass().getName(), "jdk.internal.vm.TranslatedException");
|
||||
Assert.assertEquals(decoded.toString(), "jdk.internal.vm.TranslatedException[jdk.internal.vm.test.TestTranslatedException$Untranslatable]: test exception");
|
||||
Assert.assertEquals(original.getMessage(), "test exception");
|
||||
} else {
|
||||
Assert.assertEquals(original.getClass().getName(), decoded.getClass().getName());
|
||||
Assert.assertEquals(original.getMessage(), decoded.getMessage());
|
||||
Assert.assertEquals(decoded.getClass().getName(), original.getClass().getName());
|
||||
Assert.assertEquals(decoded.getMessage(), original.getMessage());
|
||||
}
|
||||
StackTraceElement[] originalStack = original.getStackTrace();
|
||||
StackTraceElement[] decodedStack = decoded.getStackTrace();
|
||||
@ -130,12 +111,12 @@ public class TestTranslatedException {
|
||||
for (int i = 0, n = originalStack.length; i < n; ++i) {
|
||||
StackTraceElement originalStackElement = originalStack[i];
|
||||
StackTraceElement decodedStackElement = decodedStack[i];
|
||||
Assert.assertEquals(originalStackElement.getClassLoaderName(), decodedStackElement.getClassLoaderName());
|
||||
Assert.assertEquals(originalStackElement.getModuleName(), decodedStackElement.getModuleName());
|
||||
Assert.assertEquals(originalStackElement.getClassName(), decodedStackElement.getClassName());
|
||||
Assert.assertEquals(originalStackElement.getMethodName(), decodedStackElement.getMethodName());
|
||||
Assert.assertEquals(originalStackElement.getFileName(), decodedStackElement.getFileName());
|
||||
Assert.assertEquals(originalStackElement.getLineNumber(), decodedStackElement.getLineNumber());
|
||||
Assert.assertEquals(decodedStackElement.getClassLoaderName(), originalStackElement.getClassLoaderName());
|
||||
Assert.assertEquals(decodedStackElement.getModuleName(), originalStackElement.getModuleName());
|
||||
Assert.assertEquals(decodedStackElement.getClassName(), originalStackElement.getClassName());
|
||||
Assert.assertEquals(decodedStackElement.getMethodName(), originalStackElement.getMethodName());
|
||||
Assert.assertEquals(decodedStackElement.getFileName(), originalStackElement.getFileName());
|
||||
Assert.assertEquals(decodedStackElement.getLineNumber(), originalStackElement.getLineNumber());
|
||||
}
|
||||
original = original.getCause();
|
||||
decoded = decoded.getCause();
|
Loading…
x
Reference in New Issue
Block a user