Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
Expand Down Expand Up @@ -2339,7 +2339,7 @@ C2V_VMENTRY_PREFIX(void, detachCurrentThread, (JNIEnv* env, jobject c2vm))
}
C2V_END

C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jboolean callPostTranslation))
requireJVMCINativeLibrary(JVMCI_CHECK_0);
if (obj_handle == NULL) {
return 0L;
Expand Down Expand Up @@ -2390,7 +2390,9 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
const char* cstring = name_string.is_null() ? NULL : thisEnv->as_utf8_string(name_string);
// Create a new HotSpotNmethod instance in the peer runtime
result = peerEnv->new_HotSpotNmethod(mh, cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0);
if (nm == NULL) {
if (result.is_null()) {
// exception occurred (e.g. OOME) creating a new HotSpotNmethod
} else if (nm == NULL) {
// nmethod must have been unloaded
} else {
// Link the new HotSpotNmethod to the nmethod
Expand All @@ -2413,6 +2415,13 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
JVMCI_THROW_MSG_0(IllegalArgumentException,
err_msg("Cannot translate object of type: %s", thisEnv->klass_name(obj)));
}
if (callPostTranslation) {
peerEnv->call_HotSpotJVMCIRuntime_postTranslation(result, JVMCI_CHECK_0);
}
// Propagate any exception that occurred while creating the translated object
if (peerEnv->transfer_pending_exception(thread, thisEnv)) {
return 0L;
}
return (jlong) peerEnv->make_global(result).as_jobject();
}

Expand Down Expand Up @@ -2710,7 +2719,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)},
{CC "attachCurrentThread", CC "([BZ)Z", FN_PTR(attachCurrentThread)},
{CC "detachCurrentThread", CC "()V", FN_PTR(detachCurrentThread)},
{CC "translate", CC "(" OBJECT ")J", FN_PTR(translate)},
{CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)},
{CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)},
{CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)},
{CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)},
Expand Down
173 changes: 148 additions & 25 deletions src/hotspot/share/jvmci/jvmciEnv.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
Expand Down Expand Up @@ -278,35 +278,141 @@ void JVMCIEnv::describe_pending_exception(bool clear) {
}
}

void JVMCIEnv::translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable) {
assert(!is_hotspot(), "must_be");
// Resolve HotSpotJVMCIRuntime 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);
JavaCallArguments jargs;
jargs.push_oop(throwable);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
runtimeKlass,
vmSymbols::encodeThrowable_name(),
vmSymbols::encodeThrowable_signature(), &jargs, THREAD);
if (HAS_PENDING_EXCEPTION) {
JVMCIRuntime::fatal_exception(this, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception");
// Shared code for translating an exception from HotSpot to libjvmci or vice versa.
class ExceptionTranslation: public StackObj {
protected:
JVMCIEnv* _from_env; // Source of translation. Can be nullptr.
JVMCIEnv* _to_env; // Destination of translation. Never nullptr.

ExceptionTranslation(JVMCIEnv* from_env, JVMCIEnv* to_env) : _from_env(from_env), _to_env(to_env) {}

// 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;

// Decodes the exception in `buffer` in `_to_env` and throws it.
virtual void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) = 0;

public:
void doit(JavaThread* THREAD) {
// Resolve HotSpotJVMCIRuntime 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);

int buffer_size = 2048;
while (true) {
ResourceMark rm;
jlong buffer = (jlong) NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, jbyte, buffer_size);
int res = encode(THREAD, runtimeKlass, buffer, buffer_size);
if ((_from_env != nullptr && _from_env->has_pending_exception()) || HAS_PENDING_EXCEPTION) {
JVMCIRuntime::fatal_exception(_from_env, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception");
}
if (res < 0) {
int required_buffer_size = -res;
if (required_buffer_size > buffer_size) {
buffer_size = required_buffer_size;
}
} else {
decode(THREAD, runtimeKlass, buffer);
if (!_to_env->has_pending_exception()) {
JVMCIRuntime::fatal_exception(_to_env, "HotSpotJVMCIRuntime.decodeAndThrowThrowable should throw an exception");
}
return;
}
}
}
};

oop encoded_throwable_string = result.get_oop();
// Translates an exception on the HotSpot heap to an exception on the shared library heap.
class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
private:
const Handle& _throwable;

ResourceMark rm;
const char* encoded_throwable_chars = java_lang_String::as_utf8_string(encoded_throwable_string);
int encode(JavaThread* THREAD, Klass* runtimeKlass, 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,
vmSymbols::encodeThrowable_name(),
vmSymbols::encodeThrowable_signature(), &jargs, THREAD);
return result.get_jint();
}

JNIAccessMark jni(this, THREAD);
jobject jni_encoded_throwable_string = jni()->NewStringUTF(encoded_throwable_chars);
jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(),
jni_encoded_throwable_string);
jni()->Throw(jni_throwable);
void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) {
JNIAccessMark jni(_to_env, THREAD);
jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::decodeAndThrowThrowable_method(),
buffer);
}
public:
HotSpotToSharedLibraryExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, const Handle& throwable) :
ExceptionTranslation(hotspot_env, jni_env), _throwable(throwable) {}
};

// Translates an exception on the shared library heap to an exception on the HotSpot heap.
class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation {
private:
jthrowable _throwable;

int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) {
JNIAccessMark jni(_from_env, THREAD);
return jni()->CallStaticIntMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::encodeThrowable_method(),
_throwable, buffer, buffer_size);
}

void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) {
JavaCallArguments jargs;
jargs.push_long(buffer);
JavaValue result(T_VOID);
JavaCalls::call_static(&result,
runtimeKlass,
vmSymbols::decodeAndThrowThrowable_name(),
vmSymbols::long_void_signature(), &jargs, THREAD);
}
public:
SharedLibraryToHotSpotExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, jthrowable throwable) :
ExceptionTranslation(jni_env, hotspot_env), _throwable(throwable) {}
};

void JVMCIEnv::translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) {
HotSpotToSharedLibraryExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD);
}

void JVMCIEnv::translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) {
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;
}
}
return false;
}


JVMCIEnv::~JVMCIEnv() {
if (_throw_to_caller) {
if (is_hotspot()) {
Expand All @@ -318,7 +424,7 @@ JVMCIEnv::~JVMCIEnv() {
if (HAS_PENDING_EXCEPTION) {
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
translate_hotspot_exception_to_jni_exception(THREAD, throwable);
translate_to_jni_exception(THREAD, throwable, nullptr, this);
}
}
}
Expand Down Expand Up @@ -801,6 +907,23 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(JVMCIObject object,
}
}

void JVMCIEnv::call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCIEnv* JVMCIENV) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
if (is_hotspot()) {
JavaCallArguments jargs;
jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(object)));
JavaValue result(T_VOID);
JavaCalls::call_static(&result,
HotSpotJVMCI::HotSpotJVMCIRuntime::klass(),
vmSymbols::postTranslation_name(),
vmSymbols::object_void_signature(), &jargs, CHECK);
} else {
JNIAccessMark jni(this, THREAD);
jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::postTranslation_method(),
object.as_jobject());
}
}

JVMCIObject JVMCIEnv::call_JavaConstant_forPrimitive(JVMCIObject kind, jlong value, JVMCI_TRAPS) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
Expand Down
23 changes: 17 additions & 6 deletions src/hotspot/share/jvmci/jvmciEnv.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
Expand Down Expand Up @@ -171,11 +171,15 @@ class JVMCIEnv : public ResourceObj {
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
// the shared library heap. The translation includes the stack and
// causes of `throwable`. The translated exception is pending in the
// shared library thread upon returning.
void translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable);
// Translates an exception on the HotSpot heap (i.e., hotspot_env) to an exception on
// the shared library heap (i.e., jni_env). The translation includes the stack and cause(s) of `throwable`.
// The translated exception is pending in jni_env upon returning.
static void translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env);

// Translates an exception on the shared library heap (i.e., jni_env) to an exception on
// the HotSpot heap (i.e., hotspot_env). The translation includes the stack and cause(s) of `throwable`.
// 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);

public:
// Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM).
Expand Down Expand Up @@ -225,6 +229,11 @@ class JVMCIEnv : public ResourceObj {
jboolean has_pending_exception();
void clear_pending_exception();

// If this env has a pending exception, it is translated to be a pending
// exception in `peer_env` and is cleared from this env. Returns true
// if a pending exception was transferred, false otherwise.
jboolean transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env);

// Prints an exception and stack trace of a pending exception.
void describe_pending_exception(bool clear);

Expand Down Expand Up @@ -311,6 +320,8 @@ class JVMCIEnv : public ResourceObj {

jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier);

void call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCI_TRAPS);

BasicType kindToBasicType(JVMCIObject kind, JVMCI_TRAPS);

#define DO_THROW(name) \
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/jvmci/jvmciJavaClasses.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
Expand Down
5 changes: 3 additions & 2 deletions src/hotspot/share/jvmci/jvmciJavaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,13 +349,14 @@
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(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, decodeThrowable, decodeThrowable_signature, (JVMCIObject encodedThrowable)) \
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)) \
jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, HotSpotJVMCIRuntime, getCompiler, getCompiler_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, callToString, callToString_signature, (JVMCIObject object, JVMCI_TRAPS)) \
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature, (JVMCIObject object, JVMCI_TRAPS)) \
end_class \
start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \
jvmci_constructor(JVMCIError, "(Ljava/lang/String;)V") \
Expand Down
Loading