Skip to content
2 changes: 1 addition & 1 deletion src/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@
template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \
template(encodeAnnotations_name, "encodeAnnotations") \
template(encodeAnnotations_signature, "([BLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;Z[Ljava/lang/Class;)[B")\
template(decodeAndThrowThrowable_signature, "(JZ)V") \
template(decodeAndThrowThrowable_signature, "(IJZ)V") \
template(classRedefinedCount_name, "classRedefinedCount") \
template(classLoader_name, "classLoader") \
template(componentType_name, "componentType") \
Expand Down
30 changes: 19 additions & 11 deletions src/hotspot/share/jvmci/jvmciEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ class ExceptionTranslation: public StackObj {
// and the encoding was written to `buffer` otherwise returns -N.
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* vmSupport, jlong buffer) = 0;
// Decodes the exception in `format` and `buffer` in `_to_env` and throws it.
virtual void decode(JavaThread* THREAD, Klass* vmSupport, jint format, jlong buffer) = 0;

public:
void doit(JavaThread* THREAD) {
Expand All @@ -395,23 +395,30 @@ class ExceptionTranslation: public StackObj {
ResourceMark rm;
jlong buffer = (jlong) NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jbyte, buffer_size);
if (buffer == 0L) {
decode(THREAD, vmSupport, 0L);
decode(THREAD, vmSupport, -1, 0L);
return;
}
int res = encode(THREAD, vmSupport, buffer, buffer_size);
if (_from_env != nullptr && !_from_env->is_hotspot() && _from_env->has_pending_exception()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this check before the HAS_PENDING_EXCEPTION check? Couldn't you end up returning with a pending exception in this path?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If encode is SharedLibraryToHotSpotExceptionTranslation::encode there is no possibility of a pending HotSpot exception upon it returning. If it's HotSpotToSharedLibraryExceptionTranslation::encode then _from_env->is_hotspot() is true and so this if branch is not taken.

// 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, vmSupport, -2L);
decode(THREAD, vmSupport, -3, 0L);
return;
} else if (HAS_PENDING_EXCEPTION) {
Symbol *ex_name = PENDING_EXCEPTION->klass()->name();
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
Symbol *ex_name = throwable->klass()->name();
CLEAR_PENDING_EXCEPTION;
if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
decode(THREAD, vmSupport, -1L);
decode(THREAD, vmSupport, -2, 0L);
} else {
decode(THREAD, vmSupport, -2L);
char* char_buffer = (char*) buffer + 4;
stringStream st(char_buffer, (size_t) buffer_size - 4);
java_lang_Throwable::print_stack_trace(throwable, &st);
int len = st.size();
*((u4*) buffer) = len;
JVMCI_event_1("error translating exception: %s", char_buffer);
decode(THREAD, vmSupport, -3, buffer);
}
return;
} else if (res < 0) {
Expand All @@ -420,7 +427,7 @@ class ExceptionTranslation: public StackObj {
buffer_size = required_buffer_size;
}
} else {
decode(THREAD, vmSupport, buffer);
decode(THREAD, vmSupport, 0, buffer);
if (!_to_env->has_pending_exception()) {
_to_env->throw_InternalError("decodeAndThrowThrowable should have thrown an exception");
}
Expand Down Expand Up @@ -448,11 +455,11 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
return result.get_jint();
}

void decode(JavaThread* THREAD, Klass* vmSupport, jlong buffer) {
void decode(JavaThread* THREAD, Klass* vmSupport, jint format, jlong buffer) {
JNIAccessMark jni(_to_env, THREAD);
jni()->CallStaticVoidMethod(JNIJVMCI::VMSupport::clazz(),
JNIJVMCI::VMSupport::decodeAndThrowThrowable_method(),
buffer, false);
format, buffer, false);
}
public:
HotSpotToSharedLibraryExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, const Handle& throwable) :
Expand All @@ -471,8 +478,9 @@ class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation {
_throwable, buffer, buffer_size);
}

void decode(JavaThread* THREAD, Klass* vmSupport, jlong buffer) {
void decode(JavaThread* THREAD, Klass* vmSupport, jint format, jlong buffer) {
JavaCallArguments jargs;
jargs.push_int(format);
jargs.push_long(buffer);
jargs.push_int(true);
JavaValue result(T_VOID);
Expand Down
42 changes: 25 additions & 17 deletions src/java.base/share/classes/jdk/internal/vm/VMSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.IncompleteAnnotationException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
Expand Down Expand Up @@ -112,36 +113,43 @@ public static byte[] serializeAgentPropertiesToByteArray() throws IOException {
public static native String getVMTemporaryDirectory();

/**
* Decodes the exception encoded in {@code errorOrBuffer} and throws it.
*
* @param errorOrBuffer an error code or a native byte errorOrBuffer containing an exception encoded by
* {@link #encodeThrowable}. Error code values and their meanings are:
* Decodes the exception described by {@code format} and {@code buffer} and throws it.
*
* @param format specifies how to interpret {@code buffer}:
* <pre>
* 0: native memory for the errorOrBuffer could not be allocated
* -1: an OutOfMemoryError was thrown while encoding the exception
* -2: some other throwable was thrown while encoding the exception
* 0: {@code buffer} was created by {@link #encodeThrowable}
* -1: native memory for {@code buffer} could not be allocated
* -2: an OutOfMemoryError was thrown while encoding the exception
* -3: some other problem occured while encoding the exception. If {@code buffer != 0},
* it contains a {@code struct { u4 len; char[len] desc}} where {@code desc} describes the problem
* </pre>
* @param errorOrBuffer a native byte errorOrBuffer containing an exception encoded by
* {@link #encodeThrowable}
* @param buffer encoded info about the exception to throw (depends on {@code format})
* @param inJVMHeap [@code true} if executing in the JVM heap, {@code false} otherwise
*/
public static void decodeAndThrowThrowable(long errorOrBuffer, boolean inJVMHeap) throws Throwable {
if (errorOrBuffer >= -2L && errorOrBuffer <= 0) {
public static void decodeAndThrowThrowable(int format, long buffer, boolean inJVMHeap) throws Throwable {
if (format != 0) {
String context = String.format("while encoding an exception to translate it %s the JVM heap",
inJVMHeap ? "to" : "from");
if (errorOrBuffer == 0) {
if (format == -1) {
throw new InternalError("native errorOrBuffer could not be allocated " + context);
}
if (errorOrBuffer == -1L) {
if (format == -2L) {
throw new OutOfMemoryError("OutOfMemoryError occurred " + context);
}
if (format == -3L) {
byte[] bytes = bufferToBytes(buffer);
throw new InternalError("unexpected problem occurred " + context + ": " + new String(bytes, StandardCharsets.UTF_8));
}
throw new InternalError("unexpected problem occurred " + context);
}
int encodingLength = U.getInt(errorOrBuffer);
byte[] encoding = new byte[encodingLength];
U.copyMemory(null, errorOrBuffer + 4, encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, encodingLength);
throw TranslatedException.decodeThrowable(encoding);
throw TranslatedException.decodeThrowable(bufferToBytes(buffer));
}

private static byte[] bufferToBytes(long buffer) {
int len = U.getInt(buffer);
byte[] bytes = new byte[len];
U.copyMemory(null, buffer + 4, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
return bytes;
}

/**
Expand Down
3 changes: 2 additions & 1 deletion test/jdk/jdk/internal/vm/TestTranslatedException.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public void encodeDecodeTest() throws Exception {
private void encodeDecode(Throwable throwable) throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
int bufferSize = 512;
int format = 0;
long buffer = 0L;
while (true) {
buffer = unsafe.allocateMemory(bufferSize);
Expand All @@ -71,7 +72,7 @@ private void encodeDecode(Throwable throwable) throws Exception {
bufferSize = -res;
} else {
try {
VMSupport.decodeAndThrowThrowable(buffer, true);
VMSupport.decodeAndThrowThrowable(format, buffer, true);
throw new AssertionError("expected decodeAndThrowThrowable to throw an exception");
} catch (Throwable decoded) {
assertThrowableEquals(throwable, decoded);
Expand Down