Skip to content
Merged
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
9 changes: 7 additions & 2 deletions src/hotspot/share/jvmci/jvmci.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,17 @@ CompilerThread* CompilerThreadCanCallJava::update(JavaThread* current, bool new_
return nullptr;
}

CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) {
CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state, JVMCIEnv* env) {
_current = CompilerThreadCanCallJava::update(current, new_state);
_env = env;
}

CompilerThreadCanCallJava::~CompilerThreadCanCallJava() {
if (_current != nullptr) {
if (_current->_can_call_java && _env != nullptr && !_env->is_hotspot() && _current->has_pending_exception()) {
// Convert pending HotSpot exception while still inside scope that can call Java
JVMCIEnv::transfer_pending_exception_to_jni(_current, nullptr, _env);
}
_current->_can_call_java = !_current->_can_call_java;
}
}
Expand Down Expand Up @@ -209,7 +214,7 @@ void JVMCI::ensure_box_caches_initialized(TRAPS) {

// Class resolution and initialization below
// requires calling into Java
CompilerThreadCanCallJava ccj(THREAD, true);
CompilerThreadCanCallJava ccj(THREAD, true, nullptr);

for (unsigned i = 0; i < sizeof(box_classes) / sizeof(Symbol*); i++) {
Klass* k = SystemDictionary::resolve_or_fail(box_classes[i], true, CHECK);
Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/jvmci/jvmci.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@ typedef struct _jmetadata *jmetadata;
class CompilerThreadCanCallJava : StackObj {
private:
CompilerThread* _current; // Only non-null if state of thread changed
JVMCIEnv* _env; // For translating an exception from HotSpot to JNI
public:
// If the current thread is a CompilerThread associated with
// a JVMCI compiler where CompilerThread::_can_call_java != new_state,
// then _can_call_java is set to `new_state`
// Returns nullptr if no change was made, otherwise the current CompilerThread
static CompilerThread* update(JavaThread* current, bool new_state);

CompilerThreadCanCallJava(JavaThread* current, bool new_state);
CompilerThreadCanCallJava(JavaThread* current, bool new_state, JVMCIEnv* env);

// Resets CompilerThread::_can_call_java of the current thread if the
// constructor changed it.
Expand Down
12 changes: 6 additions & 6 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) {
ResourceMark rm; \
bool __is_hotspot = env == thread->jni_environment(); \
bool __block_can_call_java = __is_hotspot || !thread->is_Compiler_thread() || CompilerThread::cast(thread)->can_call_java(); \
CompilerThreadCanCallJava ccj(thread, __block_can_call_java); \
CompilerThreadCanCallJava ccj(thread, __block_can_call_java, nullptr); \
JVMCIENV_FROM_JNI(JVMCI::compilation_tick(thread), env); \

// Entry to native method implementation that transitions
Expand Down Expand Up @@ -594,7 +594,7 @@ C2V_VMENTRY_0(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, ARGUMENT_PAIR(
C2V_END

C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGUMENT_PAIR(accessing_klass), jint accessing_klass_loader, jboolean resolve))
CompilerThreadCanCallJava canCallJava(thread, resolve); // Resolution requires Java calls
CompilerThreadCanCallJava canCallJava(thread, resolve, JVMCIENV); // Resolution requires Java calls
JVMCIObject name = JVMCIENV->wrap(jname);
const char* str = JVMCIENV->as_utf8_string(name);
TempNewSymbol class_name = SymbolTable::new_symbol(str);
Expand Down Expand Up @@ -1390,7 +1390,7 @@ C2V_VMENTRY(void, reprofile, (JNIEnv* env, jobject, ARGUMENT_PAIR(method)))
if (method_data == nullptr) {
method_data = get_profiling_method_data(method, CHECK);
} else {
CompilerThreadCanCallJava canCallJava(THREAD, true);
CompilerThreadCanCallJava canCallJava(THREAD, true, JVMCIENV);
method_data->reinitialize();
}
C2V_END
Expand Down Expand Up @@ -2097,7 +2097,7 @@ C2V_VMENTRY(void, ensureInitialized, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)
C2V_END

C2V_VMENTRY(void, ensureLinked, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
CompilerThreadCanCallJava canCallJava(thread, true); // Linking requires Java calls
CompilerThreadCanCallJava canCallJava(thread, true, JVMCIENV); // Linking requires Java calls
Klass* klass = UNPACK_PAIR(Klass, klass);
if (klass == nullptr) {
JVMCI_THROW(NullPointerException);
Expand Down Expand Up @@ -2908,7 +2908,7 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool
return 0L;
}
PEER_JVMCIENV_FROM_THREAD(THREAD, !JVMCIENV->is_hotspot());
CompilerThreadCanCallJava canCallJava(thread, PEER_JVMCIENV->is_hotspot());
CompilerThreadCanCallJava canCallJava(thread, PEER_JVMCIENV->is_hotspot(), nullptr);
PEER_JVMCIENV->check_init(JVMCI_CHECK_0);

JVMCIEnv* thisEnv = JVMCIENV;
Expand Down Expand Up @@ -3221,7 +3221,7 @@ C2V_VMENTRY(void, callSystemExit, (JNIEnv* env, jobject, jint status))
vm_exit_during_initialization();
}
}
CompilerThreadCanCallJava canCallJava(thread, true);
CompilerThreadCanCallJava canCallJava(thread, true, JVMCIENV);
JavaValue result(T_VOID);
JavaCallArguments jargs(1);
jargs.push_int(status);
Expand Down
3 changes: 1 addition & 2 deletions src/hotspot/share/jvmci/jvmciEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,6 @@ DO_THROW(InvalidInstalledCodeException)
DO_THROW(UnsatisfiedLinkError)
DO_THROW(UnsupportedOperationException)
DO_THROW(OutOfMemoryError)
DO_THROW(NoClassDefFoundError)

#undef DO_THROW

Expand Down Expand Up @@ -1370,7 +1369,7 @@ JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS)
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
jboolean exception = false;
if (is_hotspot()) {
CompilerThreadCanCallJava ccj(THREAD, true);
CompilerThreadCanCallJava ccj(THREAD, true, JVMCIENV);
JavaValue result(T_OBJECT);
JavaCallArguments args;
args.push_long(pointer);
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/jvmci/jvmciEnv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,6 @@ class JVMCIEnv : public ResourceObj {
DO_THROW(UnsatisfiedLinkError)
DO_THROW(UnsupportedOperationException)
DO_THROW(OutOfMemoryError)
DO_THROW(NoClassDefFoundError)

#undef DO_THROW

Expand Down
39 changes: 0 additions & 39 deletions src/hotspot/share/jvmci/jvmciJavaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,43 +408,6 @@ extern "C" {
jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets_handle);
}

// Dumps symbols for public <init>() and <init>(String) methods of
// non-abstract Throwable subtypes known by the VM. This is to
// support the use of reflection in jdk.vm.ci.hotspot.TranslatedException.create().
class ThrowableInitDumper : public SymbolClosure {
private:
fileStream* _st;
public:
ThrowableInitDumper(fileStream* st) { _st = st; }
void do_symbol(Symbol** p) {
JavaThread* THREAD = JavaThread::current(); // For exception macros.
Symbol* name = *p;
if (name == nullptr) {
return;
}
Klass* k = SystemDictionary::resolve_or_null(name, CHECK_EXIT);
if (k != nullptr && k->is_instance_klass()) {
InstanceKlass* iklass = InstanceKlass::cast(k);
if (iklass->is_subclass_of(vmClasses::Throwable_klass()) && iklass->is_public() && !iklass->is_abstract()) {
const char* class_name = nullptr;
Array<Method*>* methods = iklass->methods();
for (int i = 0; i < methods->length(); i++) {
Method* m = methods->at(i);
if (m->name() == vmSymbols::object_initializer_name() &&
m->is_public() &&
(m->signature() == vmSymbols::void_method_signature() || m->signature() == vmSymbols::string_void_signature())) {
if (class_name == nullptr) {
class_name = name->as_C_string();
_st->print_cr("class %s", class_name);
}
_st->print_cr("method %s %s %s", class_name, m->name()->as_C_string(), m->signature()->as_C_string());
}
}
}
}
}
};

#define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string()
/**
* Initializes the JNI method and field ids used in JNIJVMCI.
Expand Down Expand Up @@ -530,8 +493,6 @@ void JNIJVMCI::initialize_ids(JNIEnv* env) {
fileStream* st = JVMCIGlobals::get_jni_config_file();

DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM());
ThrowableInitDumper dumper(st);
vmSymbols::symbols_do(&dumper);

st->flush();
tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig);
Expand Down
3 changes: 0 additions & 3 deletions src/hotspot/share/jvmci/jvmciJavaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,6 @@
start_class(OutOfMemoryError, java_lang_OutOfMemoryError) \
jvmci_constructor(OutOfMemoryError, "(Ljava/lang/String;)V") \
end_class \
start_class(NoClassDefFoundError, java_lang_NoClassDefFoundError) \
jvmci_constructor(NoClassDefFoundError, "(Ljava/lang/String;)V") \
end_class \
start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \
jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \
end_class \
Expand Down
108 changes: 82 additions & 26 deletions src/java.base/share/classes/jdk/internal/vm/TranslatedException.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
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;
Expand All @@ -42,14 +41,20 @@

/**
* Support for translating exceptions between the HotSpot heap and libjvmci heap.
*
* Successfully translated exceptions are wrapped in a TranslatedException instance.
* This allows callers to distiguish between a translated exception and an error
* <p>
* Apart from {@link OutOfMemoryError}s, successfully translated exceptions have
* {@link #TRANSLATED_MARKER} as the first element in their stack trace. This
* allows a caller to distinguish between a translated exception and an error
* that arose during translation.
*/
@SuppressWarnings("serial")
public final class TranslatedException extends Exception {

/**
* Marker frame prepended to outermost stack of a translated exception.
*/
public static final StackTraceElement TRANSLATED_MARKER = new StackTraceElement(TranslatedException.class.getName(), "translated", null, -2);

/**
* The value returned by {@link #encodeThrowable(Throwable)} when encoding
* fails due to an {@link OutOfMemoryError}.
Expand Down Expand Up @@ -114,7 +119,7 @@ public Throwable fillInStackTrace() {
private static void debugPrintStackTrace(Throwable throwable, boolean debug) {
if (debug) {
System.err.print("DEBUG: ");
throwable.printStackTrace();
throwable.printStackTrace(System.err);
}
}

Expand All @@ -130,26 +135,71 @@ private static Throwable initCause(Throwable throwable, Throwable cause, boolean
return throwable;
}

/**
* Creates an exception if {@code className} is one of the supported
* core exceptions for translation.
*
* @param className class name of exception to create
* @param message the detailed message for the exception
* @return {@code null} if {@code className} is unsupported
*/
private static Throwable newThrowable(String className, String message) {
return switch (className) {
// Exceptions
case "java.lang.ArithmeticException" -> new ArithmeticException(message);
case "java.lang.ArrayIndexOutOfBoundsException" -> new ArrayIndexOutOfBoundsException(message);
case "java.lang.ArrayStoreException" -> new ArrayStoreException(message);
case "java.lang.ClassCastException" -> new ClassCastException(message);
case "java.lang.ClassNotFoundException" -> new ClassNotFoundException(message);
case "java.lang.CloneNotSupportedException" -> new CloneNotSupportedException(message);
case "java.lang.IllegalAccessException" -> new IllegalAccessException(message);
case "java.lang.IllegalArgumentException" -> new IllegalArgumentException(message);
case "java.lang.IndexOutOfBoundsException" -> new IndexOutOfBoundsException(message);
case "java.lang.InstantiationException" -> new InstantiationException(message);
case "java.lang.NegativeArraySizeException" -> new NegativeArraySizeException(message);
case "java.lang.NoSuchFieldException" -> new NoSuchFieldException(message);
case "java.lang.NoSuchMethodException" -> new NoSuchMethodException(message);
case "java.lang.NullPointerException" -> new NullPointerException(message);
case "java.lang.RuntimeException" -> new RuntimeException(message);
case "java.lang.StringIndexOutOfBoundsException" -> new StringIndexOutOfBoundsException(message);
case "java.lang.UnsupportedOperationException" -> new UnsupportedOperationException(message);

// Errors
case "java.lang.AbstractMethodError" -> new AbstractMethodError(message);
case "java.lang.BootstrapMethodError" -> new BootstrapMethodError(message);
case "java.lang.ClassCircularityError" -> new ClassCircularityError(message);
case "java.lang.ClassFormatError" -> new ClassFormatError(message);
case "java.lang.IllegalAccessError" -> new IllegalAccessError(message);
case "java.lang.IncompatibleClassChangeError" -> new IncompatibleClassChangeError(message);
case "java.lang.InstantiationError" -> new InstantiationError(message);
case "java.lang.InternalError" -> new InternalError(message);
case "java.lang.LinkageError" -> new LinkageError(message);
case "java.lang.NoClassDefFoundError" -> new NoClassDefFoundError(message);
case "java.lang.NoSuchFieldError" -> new NoSuchFieldError(message);
case "java.lang.NoSuchMethodError" -> new NoSuchMethodError(message);
case "java.lang.OutOfMemoryError" -> new OutOfMemoryError(message);
case "java.lang.StackOverflowError" -> new StackOverflowError(message);
case "java.lang.UnsatisfiedLinkError" -> new UnsatisfiedLinkError(message);
default -> null;
};
}

private static Throwable create(String className, String message, Throwable cause, boolean debug) {
// Try create with reflection first.
try {
Class<?> cls = Class.forName(className);
if (cause != null) {
// Handle known exception types whose cause must
// be set in the constructor
if (cls == InvocationTargetException.class) {
return new InvocationTargetException(cause, message);
}
if (cls == ExceptionInInitializerError.class) {
return new ExceptionInInitializerError(cause);
}
if (className.equals(InvocationTargetException.class.getName())) {
return new InvocationTargetException(cause, message);
}
if (message == null) {
Constructor<?> cons = cls.getConstructor();
return initCause((Throwable) cons.newInstance(), cause, debug);
if (className.equals(ExceptionInInitializerError.class.getName())) {
return new ExceptionInInitializerError(cause);
}
Constructor<?> cons = cls.getDeclaredConstructor(String.class);
return initCause((Throwable) cons.newInstance(message), cause, debug);
if (className.equals(AssertionError.class.getName())) {
return initCause(new AssertionError(cause), cause,debug);
}
Throwable throwable = newThrowable(className, message);
if (throwable != null) {
return initCause(throwable, cause,debug);
}
return initCause(translationFailure("%s [%s]", message, className), cause, debug);
} catch (Throwable translationFailure) {
debugPrintStackTrace(translationFailure, debug);
return initCause(translationFailure("%s [%s]", message, className), cause, debug);
Expand Down Expand Up @@ -190,7 +240,7 @@ private static byte[] encodeThrowable(Throwable throwable,
}
}

// Encode from inner most cause outwards
// Encode from innermost cause outwards
Collections.reverse(throwables);

for (Throwable current : throwables) {
Expand All @@ -201,8 +251,7 @@ private static byte[] encodeThrowable(Throwable throwable,
stackTrace = new StackTraceElement[0];
}
dos.writeInt(stackTrace.length);
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement frame = stackTrace[i];
for (StackTraceElement frame : stackTrace) {
if (frame != null) {
dos.writeUTF(emptyIfNull(frame.getClassLoaderName()));
dos.writeUTF(emptyIfNull(frame.getModuleName()));
Expand Down Expand Up @@ -294,13 +343,20 @@ static Throwable decodeThrowable(byte[] encodedThrowable, boolean debug) {
// Remove null entries at end of stackTrace
stackTrace = Arrays.copyOf(stackTrace, stackTraceIndex);
}
if (dis.available() == 0) {
// Prepend the marker frame to the outermost stack trace
StackTraceElement[] newStackTrace = new StackTraceElement[stackTrace.length + 1];
System.arraycopy(stackTrace, 0, newStackTrace, 1, stackTrace.length);
newStackTrace[0] = TRANSLATED_MARKER;
stackTrace = newStackTrace;
}
throwable.setStackTrace(stackTrace);
cause = throwable;
}
return new TranslatedException(throwable);
return throwable;
} catch (Throwable translationFailure) {
debugPrintStackTrace(translationFailure, debug);
return translationFailure("error decoding exception: %s", encodedThrowable);
return translationFailure("error decoding exception: %s", Arrays.toString(encodedThrowable));
}
}
}
2 changes: 1 addition & 1 deletion src/java.base/share/classes/jdk/internal/vm/VMSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public static byte[] serializeAgentPropertiesToByteArray() throws IOException {
public static void decodeAndThrowThrowable(int format, long buffer, boolean inJVMHeap, boolean debug) throws Throwable {
if (format != 0) {
if (format == 4) {
throw new TranslatedException(new OutOfMemoryError("in VM code and current thread cannot call Java"));
throw new OutOfMemoryError("in VM code and current thread cannot call Java");
}
String context = String.format("while encoding an exception to translate it %s the JVM heap",
inJVMHeap ? "to" : "from");
Expand Down
Loading
Loading