8308151: [JVMCI] capture JVMCI exceptions in hs-err
Reviewed-by: never
This commit is contained in:
parent
beb75e651f
commit
05c095cf39
@ -152,6 +152,8 @@ class JVMCI : public AllStatic {
|
|||||||
|
|
||||||
static void initialize_globals();
|
static void initialize_globals();
|
||||||
|
|
||||||
|
// Called to force initialization of the JVMCI compiler
|
||||||
|
// early in VM startup.
|
||||||
static void initialize_compiler(TRAPS);
|
static void initialize_compiler(TRAPS);
|
||||||
|
|
||||||
// Ensures the boxing cache classes (e.g., java.lang.Integer.IntegerCache) are initialized.
|
// Ensures the boxing cache classes (e.g., java.lang.Integer.IntegerCache) are initialized.
|
||||||
|
@ -2408,7 +2408,7 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas
|
|||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
runtime = JVMCI::compiler_runtime(thread);
|
runtime = JVMCI::compiler_runtime(thread);
|
||||||
if (peerEnv->has_pending_exception()) {
|
if (peerEnv->has_pending_exception()) {
|
||||||
peerEnv->describe_pending_exception(true);
|
peerEnv->describe_pending_exception(tty);
|
||||||
}
|
}
|
||||||
sl_handle = JVMCI::get_shared_library(sl_path, false);
|
sl_handle = JVMCI::get_shared_library(sl_path, false);
|
||||||
if (sl_handle == nullptr) {
|
if (sl_handle == nullptr) {
|
||||||
@ -2577,7 +2577,7 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb
|
|||||||
HandleMark hm(thread);
|
HandleMark hm(thread);
|
||||||
JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerJVMCIEnv);
|
JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerJVMCIEnv);
|
||||||
if (peerJVMCIEnv->has_pending_exception()) {
|
if (peerJVMCIEnv->has_pending_exception()) {
|
||||||
peerJVMCIEnv->describe_pending_exception(true);
|
peerJVMCIEnv->describe_pending_exception(tty);
|
||||||
}
|
}
|
||||||
char* sl_path;
|
char* sl_path;
|
||||||
if (JVMCI::get_shared_library(sl_path, false) == nullptr) {
|
if (JVMCI::get_shared_library(sl_path, false) == nullptr) {
|
||||||
|
@ -311,25 +311,138 @@ void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, bool jni_enomem_is_fata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a pending exception (if any) and its stack trace.
|
// Prints a pending exception (if any) and its stack trace to st.
|
||||||
void JVMCIEnv::describe_pending_exception(bool clear) {
|
// Also partially logs the stack trace to the JVMCI event log.
|
||||||
JavaThread* THREAD = JavaThread::current(); // For exception macros.
|
void JVMCIEnv::describe_pending_exception(outputStream* st) {
|
||||||
if (!is_hotspot()) {
|
ResourceMark rm;
|
||||||
JNIAccessMark jni(this, THREAD);
|
char* stack_trace = nullptr;
|
||||||
if (jni()->ExceptionCheck()) {
|
if (pending_exception_as_string(nullptr, (const char**) &stack_trace)) {
|
||||||
jthrowable ex = !clear ? jni()->ExceptionOccurred() : nullptr;
|
st->print_raw_cr(stack_trace);
|
||||||
jni()->ExceptionDescribe();
|
|
||||||
if (ex != nullptr) {
|
// Use up to half the lines of the JVMCI event log to
|
||||||
jni()->Throw(ex);
|
// show the stack trace.
|
||||||
|
char* cursor = stack_trace;
|
||||||
|
int line = 0;
|
||||||
|
const int max_lines = LogEventsBufferEntries / 2;
|
||||||
|
char* last_line = nullptr;
|
||||||
|
while (*cursor != '\0') {
|
||||||
|
char* eol = strchr(cursor, '\n');
|
||||||
|
if (eol == nullptr) {
|
||||||
|
if (line == max_lines - 1) {
|
||||||
|
last_line = cursor;
|
||||||
|
} else if (line < max_lines) {
|
||||||
|
JVMCI_event_1("%s", cursor);
|
||||||
|
}
|
||||||
|
cursor = cursor + strlen(cursor);
|
||||||
|
} else {
|
||||||
|
*eol = '\0';
|
||||||
|
if (line == max_lines - 1) {
|
||||||
|
last_line = cursor;
|
||||||
|
} else if (line < max_lines) {
|
||||||
|
JVMCI_event_1("%s", cursor);
|
||||||
|
}
|
||||||
|
cursor = eol + 1;
|
||||||
}
|
}
|
||||||
|
line++;
|
||||||
}
|
}
|
||||||
} else {
|
if (last_line != nullptr) {
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (line > max_lines) {
|
||||||
JVMCIRuntime::describe_pending_hotspot_exception(THREAD, clear);
|
JVMCI_event_1("%s [elided %d more stack trace lines]", last_line, line - max_lines);
|
||||||
|
} else {
|
||||||
|
JVMCI_event_1("%s", last_line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JVMCIEnv::pending_exception_as_string(const char** to_string, const char** stack_trace) {
|
||||||
|
JavaThread* THREAD = JavaThread::current(); // For exception macros.
|
||||||
|
JVMCIObject to_string_obj;
|
||||||
|
JVMCIObject stack_trace_obj;
|
||||||
|
bool had_nested_exception = false;
|
||||||
|
if (!is_hotspot()) {
|
||||||
|
JNIAccessMark jni(this, THREAD);
|
||||||
|
jthrowable ex = jni()->ExceptionOccurred();
|
||||||
|
if (ex != NULL) {
|
||||||
|
jni()->ExceptionClear();
|
||||||
|
jobjectArray pair = (jobjectArray) jni()->CallStaticObjectMethod(
|
||||||
|
JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
|
||||||
|
JNIJVMCI::HotSpotJVMCIRuntime::exceptionToString_method(),
|
||||||
|
ex, to_string != nullptr, stack_trace != nullptr);
|
||||||
|
if (jni()->ExceptionCheck()) {
|
||||||
|
// As last resort, dump nested exception
|
||||||
|
jni()->ExceptionDescribe();
|
||||||
|
had_nested_exception = true;
|
||||||
|
} else {
|
||||||
|
guarantee(pair != nullptr, "pair is null");
|
||||||
|
int len = jni()->GetArrayLength(pair);
|
||||||
|
guarantee(len == 2, "bad len is %d", len);
|
||||||
|
if (to_string != nullptr) {
|
||||||
|
to_string_obj = JVMCIObject::create(jni()->GetObjectArrayElement(pair, 0), false);
|
||||||
|
}
|
||||||
|
if (stack_trace != nullptr) {
|
||||||
|
stack_trace_obj = JVMCIObject::create(jni()->GetObjectArrayElement(pair, 1), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
Handle exception(THREAD, PENDING_EXCEPTION);
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
JavaCallArguments jargs;
|
||||||
|
jargs.push_oop(exception);
|
||||||
|
jargs.push_int(to_string != nullptr);
|
||||||
|
jargs.push_int(stack_trace != nullptr);
|
||||||
|
JavaValue result(T_OBJECT);
|
||||||
|
JavaCalls::call_static(&result,
|
||||||
|
HotSpotJVMCI::HotSpotJVMCIRuntime::klass(),
|
||||||
|
vmSymbols::exceptionToString_name(),
|
||||||
|
vmSymbols::exceptionToString_signature(), &jargs, THREAD);
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
Handle nested_exception(THREAD, PENDING_EXCEPTION);
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
java_lang_Throwable::print_stack_trace(nested_exception, tty);
|
||||||
|
// Clear and ignore any exceptions raised during printing
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
had_nested_exception = true;
|
||||||
|
} else {
|
||||||
|
oop pair = result.get_oop();
|
||||||
|
guarantee(pair->is_objArray(), "must be");
|
||||||
|
objArrayOop pair_arr = objArrayOop(pair);
|
||||||
|
int len = pair_arr->length();
|
||||||
|
guarantee(len == 2, "bad len is %d", len);
|
||||||
|
if (to_string != nullptr) {
|
||||||
|
to_string_obj = HotSpotJVMCI::wrap(pair_arr->obj_at(0));
|
||||||
|
}
|
||||||
|
if (stack_trace != nullptr) {
|
||||||
|
stack_trace_obj = HotSpotJVMCI::wrap(pair_arr->obj_at(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (had_nested_exception) {
|
||||||
|
if (to_string != nullptr) {
|
||||||
|
*to_string = "nested exception occurred converting exception to string";
|
||||||
|
}
|
||||||
|
if (stack_trace != nullptr) {
|
||||||
|
*stack_trace = "nested exception occurred converting exception stack to string";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (to_string_obj.is_non_null()) {
|
||||||
|
*to_string = as_utf8_string(to_string_obj);
|
||||||
|
}
|
||||||
|
if (stack_trace_obj.is_non_null()) {
|
||||||
|
*stack_trace = as_utf8_string(stack_trace_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Shared code for translating an exception from HotSpot to libjvmci or vice versa.
|
// Shared code for translating an exception from HotSpot to libjvmci or vice versa.
|
||||||
class ExceptionTranslation: public StackObj {
|
class ExceptionTranslation: public StackObj {
|
||||||
protected:
|
protected:
|
||||||
@ -771,10 +884,11 @@ const char* JVMCIEnv::as_utf8_string(JVMCIObject str) {
|
|||||||
return java_lang_String::as_utf8_string(HotSpotJVMCI::resolve(str));
|
return java_lang_String::as_utf8_string(HotSpotJVMCI::resolve(str));
|
||||||
} else {
|
} else {
|
||||||
JNIAccessMark jni(this);
|
JNIAccessMark jni(this);
|
||||||
int length = jni()->GetStringLength(str.as_jstring());
|
jstring jstr = str.as_jstring();
|
||||||
int utf8_length = jni()->GetStringUTFLength(str.as_jstring());
|
int length = jni()->GetStringLength(jstr);
|
||||||
|
int utf8_length = jni()->GetStringUTFLength(jstr);
|
||||||
char* result = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
|
char* result = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
|
||||||
jni()->GetStringUTFRegion(str.as_jstring(), 0, length, result);
|
jni()->GetStringUTFRegion(jstr, 0, length, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -904,7 +1018,7 @@ void JVMCIEnv::call_HotSpotJVMCIRuntime_shutdown (JVMCIObject runtime) {
|
|||||||
if (has_pending_exception()) {
|
if (has_pending_exception()) {
|
||||||
// This should never happen as HotSpotJVMCIRuntime.shutdown() should
|
// This should never happen as HotSpotJVMCIRuntime.shutdown() should
|
||||||
// handle all exceptions.
|
// handle all exceptions.
|
||||||
describe_pending_exception(true);
|
describe_pending_exception(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -960,30 +1074,6 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_getCompiler (JVMCIObject runtime,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(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_OBJECT);
|
|
||||||
JavaCalls::call_static(&result,
|
|
||||||
HotSpotJVMCI::HotSpotJVMCIRuntime::klass(),
|
|
||||||
vmSymbols::callToString_name(),
|
|
||||||
vmSymbols::callToString_signature(), &jargs, CHECK_(JVMCIObject()));
|
|
||||||
return wrap(result.get_oop());
|
|
||||||
} else {
|
|
||||||
JNIAccessMark jni(this, THREAD);
|
|
||||||
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
|
|
||||||
JNIJVMCI::HotSpotJVMCIRuntime::callToString_method(),
|
|
||||||
object.as_jobject());
|
|
||||||
if (jni()->ExceptionCheck()) {
|
|
||||||
return JVMCIObject();
|
|
||||||
}
|
|
||||||
return wrap(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JVMCIEnv::call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCIEnv* JVMCIENV) {
|
void JVMCIEnv::call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCIEnv* JVMCIENV) {
|
||||||
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
|
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
|
||||||
if (is_hotspot()) {
|
if (is_hotspot()) {
|
||||||
|
@ -258,10 +258,16 @@ public:
|
|||||||
// Returns true if a pending exception was transferred, false otherwise.
|
// 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);
|
static jboolean transfer_pending_exception_to_jni(JavaThread* THREAD, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env);
|
||||||
|
|
||||||
// Prints the toString() and stack trace of a pending exception.
|
// Prints the stack trace of a pending exception to `st` and clears the exception.
|
||||||
// If there is no pending exception, this is a nop.
|
// If there is no pending exception, this is a nop.
|
||||||
// If `clear` is false, the pending exception will remain pending upon return.
|
void describe_pending_exception(outputStream* st);
|
||||||
void describe_pending_exception(bool clear);
|
|
||||||
|
// Gets the output of calling toString and/or printStactTrace on the pending exception.
|
||||||
|
// If to_string is not null, the output of toString is returned in it.
|
||||||
|
// If stack_trace is not null, the output of printStackTrace is returned in it.
|
||||||
|
// Returns false if there is no pending exception otherwise clears the pending
|
||||||
|
// exception and returns true.
|
||||||
|
bool pending_exception_as_string(const char** to_string, const char** stack_trace);
|
||||||
|
|
||||||
int get_length(JVMCIArray array);
|
int get_length(JVMCIArray array);
|
||||||
|
|
||||||
@ -342,8 +348,6 @@ public:
|
|||||||
JVMCIObject call_JVMCI_getRuntime(JVMCI_TRAPS);
|
JVMCIObject call_JVMCI_getRuntime(JVMCI_TRAPS);
|
||||||
JVMCIObject call_HotSpotJVMCIRuntime_getCompiler(JVMCIObject runtime, JVMCI_TRAPS);
|
JVMCIObject call_HotSpotJVMCIRuntime_getCompiler(JVMCIObject runtime, JVMCI_TRAPS);
|
||||||
|
|
||||||
JVMCIObject call_HotSpotJVMCIRuntime_callToString(JVMCIObject object, JVMCI_TRAPS);
|
|
||||||
|
|
||||||
JVMCIObject call_JavaConstant_forPrimitive(jchar type_char, jlong value, JVMCI_TRAPS);
|
JVMCIObject call_JavaConstant_forPrimitive(jchar type_char, jlong value, JVMCI_TRAPS);
|
||||||
|
|
||||||
jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier);
|
jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier);
|
||||||
|
@ -72,7 +72,7 @@ class JVMCIEnv;
|
|||||||
|
|
||||||
#define JVMCI_CATCH \
|
#define JVMCI_CATCH \
|
||||||
JVMCIENV); if (JVMCI_HAS_PENDING_EXCEPTION) { \
|
JVMCIENV); if (JVMCI_HAS_PENDING_EXCEPTION) { \
|
||||||
JVMCIENV->describe_pending_exception(true); \
|
JVMCIENV->describe_pending_exception(tty); \
|
||||||
ShouldNotReachHere(); \
|
ShouldNotReachHere(); \
|
||||||
} (void)(0
|
} (void)(0
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@
|
|||||||
jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \
|
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(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(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(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, exceptionToString, exceptionToString_signature, (JVMCIObject object, bool toString, bool stackTrace, JVMCI_TRAPS)) \
|
||||||
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature, (JVMCIObject object, JVMCI_TRAPS)) \
|
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature, (JVMCIObject object, JVMCI_TRAPS)) \
|
||||||
end_class \
|
end_class \
|
||||||
start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \
|
start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "jvmci/jvmciRuntime.hpp"
|
#include "jvmci/jvmciRuntime.hpp"
|
||||||
#include "jvmci/metadataHandles.hpp"
|
#include "jvmci/metadataHandles.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
|
#include "logging/logStream.hpp"
|
||||||
#include "memory/oopFactory.hpp"
|
#include "memory/oopFactory.hpp"
|
||||||
#include "memory/universe.hpp"
|
#include "memory/universe.hpp"
|
||||||
#include "oops/constantPool.inline.hpp"
|
#include "oops/constantPool.inline.hpp"
|
||||||
@ -1610,19 +1611,14 @@ void JVMCIRuntime::bootstrap_finished(TRAPS) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JVMCIRuntime::describe_pending_hotspot_exception(JavaThread* THREAD, bool clear) {
|
void JVMCIRuntime::describe_pending_hotspot_exception(JavaThread* THREAD) {
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
Handle exception(THREAD, PENDING_EXCEPTION);
|
Handle exception(THREAD, PENDING_EXCEPTION);
|
||||||
const char* exception_file = THREAD->exception_file();
|
|
||||||
int exception_line = THREAD->exception_line();
|
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
java_lang_Throwable::print_stack_trace(exception, tty);
|
java_lang_Throwable::print_stack_trace(exception, tty);
|
||||||
|
|
||||||
// Clear and ignore any exceptions raised during printing
|
// Clear and ignore any exceptions raised during printing
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
if (!clear) {
|
|
||||||
THREAD->set_pending_exception(exception(), exception_file, exception_line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1635,15 +1631,15 @@ void JVMCIRuntime::fatal_exception(JVMCIEnv* JVMCIENV, const char* message) {
|
|||||||
// Only report an error once
|
// Only report an error once
|
||||||
tty->print_raw_cr(message);
|
tty->print_raw_cr(message);
|
||||||
if (JVMCIENV != nullptr) {
|
if (JVMCIENV != nullptr) {
|
||||||
JVMCIENV->describe_pending_exception(true);
|
JVMCIENV->describe_pending_exception(tty);
|
||||||
} else {
|
} else {
|
||||||
describe_pending_hotspot_exception(THREAD, true);
|
describe_pending_hotspot_exception(THREAD);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Allow error reporting thread to print the stack trace.
|
// Allow error reporting thread time to print the stack trace.
|
||||||
THREAD->sleep(200);
|
THREAD->sleep(200);
|
||||||
}
|
}
|
||||||
fatal("Fatal exception in JVMCI: %s", message);
|
fatal("Fatal JVMCI exception (see JVMCI Events for stack trace): %s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
@ -1992,19 +1988,25 @@ JVMCI::CodeInstallResult JVMCIRuntime::validate_compile_task_dependencies(Depend
|
|||||||
// Otherwise, it returns false.
|
// Otherwise, it returns false.
|
||||||
static bool after_compiler_upcall(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, const methodHandle& method, const char* function) {
|
static bool after_compiler_upcall(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, const methodHandle& method, const char* function) {
|
||||||
if (JVMCIENV->has_pending_exception()) {
|
if (JVMCIENV->has_pending_exception()) {
|
||||||
|
ResourceMark rm;
|
||||||
bool reason_on_C_heap = true;
|
bool reason_on_C_heap = true;
|
||||||
const char* failure_reason = os::strdup(err_msg("uncaught exception in %s", function), mtJVMCI);
|
const char* pending_string = nullptr;
|
||||||
|
const char* pending_stack_trace = nullptr;
|
||||||
|
JVMCIENV->pending_exception_as_string(&pending_string, &pending_stack_trace);
|
||||||
|
if (pending_string == nullptr) pending_string = "null";
|
||||||
|
const char* failure_reason = os::strdup(err_msg("uncaught exception in %s [%s]", function, pending_string), mtJVMCI);
|
||||||
if (failure_reason == nullptr) {
|
if (failure_reason == nullptr) {
|
||||||
failure_reason = "uncaught exception";
|
failure_reason = "uncaught exception";
|
||||||
reason_on_C_heap = false;
|
reason_on_C_heap = false;
|
||||||
}
|
}
|
||||||
|
JVMCI_event_1("%s", failure_reason);
|
||||||
Log(jit, compilation) log;
|
Log(jit, compilation) log;
|
||||||
if (log.is_info()) {
|
if (log.is_info()) {
|
||||||
ResourceMark rm;
|
|
||||||
log.info("%s while compiling %s", failure_reason, method->name_and_sig_as_C_string());
|
log.info("%s while compiling %s", failure_reason, method->name_and_sig_as_C_string());
|
||||||
JVMCIENV->describe_pending_exception(true);
|
if (pending_stack_trace != nullptr) {
|
||||||
} else {
|
LogStream ls(log.info());
|
||||||
JVMCIENV->clear_pending_exception();
|
ls.print_raw_cr(pending_stack_trace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
JVMCICompileState* compile_state = JVMCIENV->compile_state();
|
JVMCICompileState* compile_state = JVMCIENV->compile_state();
|
||||||
compile_state->set_failure(true, failure_reason, reason_on_C_heap);
|
compile_state->set_failure(true, failure_reason, reason_on_C_heap);
|
||||||
@ -2049,6 +2051,13 @@ void JVMCIRuntime::compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, c
|
|||||||
|
|
||||||
JVMCIObject result_object = JVMCIENV->call_HotSpotJVMCIRuntime_compileMethod(receiver, jvmci_method, entry_bci,
|
JVMCIObject result_object = JVMCIENV->call_HotSpotJVMCIRuntime_compileMethod(receiver, jvmci_method, entry_bci,
|
||||||
(jlong) compile_state, compile_state->task()->compile_id());
|
(jlong) compile_state, compile_state->task()->compile_id());
|
||||||
|
if (JVMCIENV->has_pending_exception()) {
|
||||||
|
const char* val = Arguments::PropertyList_get_value(Arguments::system_properties(), "test.jvmci.compileMethodExceptionIsFatal");
|
||||||
|
if (val != nullptr && strcmp(val, "true") == 0) {
|
||||||
|
fatal_exception(JVMCIENV, "testing JVMCI fatal exception handling");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (after_compiler_upcall(JVMCIENV, compiler, method, "call_HotSpotJVMCIRuntime_compileMethod")) {
|
if (after_compiler_upcall(JVMCIENV, compiler, method, "call_HotSpotJVMCIRuntime_compileMethod")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -469,7 +469,7 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
|
|||||||
// Reports an unexpected exception and exits the VM with a fatal error.
|
// Reports an unexpected exception and exits the VM with a fatal error.
|
||||||
static void fatal_exception(JVMCIEnv* JVMCIENV, const char* message);
|
static void fatal_exception(JVMCIEnv* JVMCIENV, const char* message);
|
||||||
|
|
||||||
static void describe_pending_hotspot_exception(JavaThread* THREAD, bool clear);
|
static void describe_pending_hotspot_exception(JavaThread* THREAD);
|
||||||
|
|
||||||
#define CHECK_EXIT THREAD); \
|
#define CHECK_EXIT THREAD); \
|
||||||
if (HAS_PENDING_EXCEPTION) { \
|
if (HAS_PENDING_EXCEPTION) { \
|
||||||
|
@ -94,8 +94,8 @@
|
|||||||
template(runtime_signature, "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;") \
|
template(runtime_signature, "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;") \
|
||||||
template(getCompiler_name, "getCompiler") \
|
template(getCompiler_name, "getCompiler") \
|
||||||
template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \
|
template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \
|
||||||
template(callToString_name, "callToString") \
|
template(exceptionToString_name, "exceptionToString") \
|
||||||
template(callToString_signature, "(Ljava/lang/Object;)Ljava/lang/String;") \
|
template(exceptionToString_signature, "(Ljava/lang/Throwable;ZZ)[Ljava/lang/String;") \
|
||||||
template(postTranslation_name, "postTranslation") \
|
template(postTranslation_name, "postTranslation") \
|
||||||
template(getName_name, "getName") \
|
template(getName_name, "getName") \
|
||||||
template(bootstrapFinished_name, "bootstrapFinished") \
|
template(bootstrapFinished_name, "bootstrapFinished") \
|
||||||
|
@ -28,6 +28,7 @@ import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
|
|||||||
import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
|
import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -39,6 +40,7 @@ import java.lang.reflect.Executable;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Formatter;
|
import java.util.Formatter;
|
||||||
@ -198,8 +200,19 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VMEntryPoint
|
@VMEntryPoint
|
||||||
static String callToString(Object o) {
|
static String[] exceptionToString(Throwable o, boolean toString, boolean stackTrace) {
|
||||||
return o.toString();
|
String[] res = {null, null};
|
||||||
|
if (toString) {
|
||||||
|
res[0] = o.toString();
|
||||||
|
}
|
||||||
|
if (stackTrace) {
|
||||||
|
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||||
|
try (PrintStream ps = new PrintStream(buf)) {
|
||||||
|
o.printStackTrace(ps);
|
||||||
|
}
|
||||||
|
res[1] = buf.toString(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
compiler.jvmci.TestUncaughtErrorInCompileMethod
|
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, 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
|
||||||
|
* @summary Tests handling of an exception thrown by HotSpotJVMCIRuntime.compileMethod.
|
||||||
|
* @requires vm.jvmci
|
||||||
|
* @library /test/lib /
|
||||||
|
* @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.internal.vm.ci/jdk.vm.ci.code
|
||||||
|
* jdk.internal.vm.ci/jdk.vm.ci.meta
|
||||||
|
* jdk.internal.vm.ci/jdk.vm.ci.runtime
|
||||||
|
* jdk.internal.vm.ci/jdk.vm.ci.services
|
||||||
|
* @run driver jdk.test.lib.FileInstaller ./TestUncaughtErrorInCompileMethod.config
|
||||||
|
* ./META-INF/services/jdk.vm.ci.services.JVMCIServiceLocator
|
||||||
|
* @run driver compiler.jvmci.TestUncaughtErrorInCompileMethod
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.jvmci;
|
||||||
|
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
import jdk.vm.ci.services.JVMCIServiceLocator;
|
||||||
|
import jdk.vm.ci.runtime.JVMCICompiler;
|
||||||
|
import jdk.vm.ci.runtime.JVMCICompilerFactory;
|
||||||
|
import jdk.vm.ci.runtime.JVMCIRuntime;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class TestUncaughtErrorInCompileMethod extends JVMCIServiceLocator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of file whose existence implies that a JVMCICompiler has been created.
|
||||||
|
*/
|
||||||
|
static String tmpFileName = "ErrorCompilerCreated." + System.nanoTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param args if args.length != 0, then executing in subprocess
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
if (args.length == 0) {
|
||||||
|
testSubprocess(false);
|
||||||
|
testSubprocess(true);
|
||||||
|
} else {
|
||||||
|
File watch = new File(tmpFileName);
|
||||||
|
int total = 0;
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Use a 10 sec timeout to prevent endless loop if
|
||||||
|
// JVMCI compiler creation fails
|
||||||
|
while (System.currentTimeMillis() - start < 10_000) {
|
||||||
|
total += getTime();
|
||||||
|
if (watch.exists()) {
|
||||||
|
System.err.println("saw " + watch + " - exiting loop");
|
||||||
|
watch.delete();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println(total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getTime() {
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testSubprocess(boolean fatalError) throws Exception {
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||||
|
"-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:+UseJVMCICompiler", "-Djvmci.Compiler=ErrorCompiler",
|
||||||
|
"-XX:-TieredCompilation",
|
||||||
|
"-XX:+PrintCompilation",
|
||||||
|
"--add-exports=jdk.internal.vm.ci/jdk.vm.ci.services=ALL-UNNAMED",
|
||||||
|
"-Dtest.jvmci.compileMethodExceptionIsFatal=" + (fatalError ? "true" : "false"),
|
||||||
|
"-XX:+PrintWarnings",
|
||||||
|
"-Xbootclasspath/a:.",
|
||||||
|
TestUncaughtErrorInCompileMethod.class.getName(), "true");
|
||||||
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
|
if (fatalError) {
|
||||||
|
output.shouldContain("testing JVMCI fatal exception handling");
|
||||||
|
output.shouldNotHaveExitValue(0);
|
||||||
|
File hs_err_file = openHsErrFileFromOutput(output);
|
||||||
|
Path hsErrPath = hs_err_file.toPath();
|
||||||
|
if (!Files.exists(hsErrPath)) {
|
||||||
|
throw new RuntimeException("hs_err_pid file missing at " + hsErrPath);
|
||||||
|
}
|
||||||
|
String hsErr = Files.readString(hsErrPath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JVMCI Events (11 events):
|
||||||
|
* ...
|
||||||
|
* Event: 0.274 Thread 0x0000000146819210 compiler.jvmci.TestUncaughtErrorInCompileMethod$CompilerCreationError
|
||||||
|
* Event: 0.274 Thread 0x0000000146819210 at compiler.jvmci.TestUncaughtErrorInCompileMethod$1.createCompiler(TestUncaughtErrorInCompileMethod.java:147)
|
||||||
|
* Event: 0.274 Thread 0x0000000146819210 at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.getCompiler(HotSpotJVMCIRuntime.java:829)
|
||||||
|
* Event: 0.274 Thread 0x0000000146819210 at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.compileMethod(HotSpotJVMCIRuntime.java:943)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check that hs-err contains the stack trace of the fatal exception (sample shown above)
|
||||||
|
String[] stackTraceSubstrings = {
|
||||||
|
"at compiler.jvmci.TestUncaughtErrorInCompileMethod$1.createCompiler(TestUncaughtErrorInCompileMethod.java",
|
||||||
|
"at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.compileMethod(HotSpotJVMCIRuntime.java"
|
||||||
|
};
|
||||||
|
for (String expect : stackTraceSubstrings) {
|
||||||
|
if (!hsErr.contains(expect)) {
|
||||||
|
throw new RuntimeException("Could not find \"" + expect + "\" in " + hsErrPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output.shouldContain("COMPILE SKIPPED: uncaught exception in call_HotSpotJVMCIRuntime_compileMethod [compiler.jvmci.TestUncaughtErrorInCompileMethod$CompilerCreationError");
|
||||||
|
output.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestUncaughtErrorInCompileMethod() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CompilerCreationError extends InternalError {
|
||||||
|
CompilerCreationError(int attempt) {
|
||||||
|
super("attempt " + attempt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <S> S getProvider(Class<S> service) {
|
||||||
|
if (service == JVMCICompilerFactory.class) {
|
||||||
|
return service.cast(new JVMCICompilerFactory() {
|
||||||
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
|
@Override
|
||||||
|
public String getCompilerName() {
|
||||||
|
return "ErrorCompiler";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JVMCICompiler createCompiler(JVMCIRuntime runtime) {
|
||||||
|
int attempt = counter.incrementAndGet();
|
||||||
|
CompilerCreationError e = new CompilerCreationError(attempt);
|
||||||
|
e.printStackTrace();
|
||||||
|
if (attempt == 10) {
|
||||||
|
// Delay the creation of the file that causes the
|
||||||
|
// loop in main to exit so that compilation failures
|
||||||
|
// have time to be reported by -XX:+PrintCompilation.
|
||||||
|
File watch = new File(tmpFileName);
|
||||||
|
try {
|
||||||
|
System.err.println("creating " + watch);
|
||||||
|
watch.createNewFile();
|
||||||
|
System.err.println("created " + watch);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the output of a java VM that crashed, extract the name of the hs-err file from the output
|
||||||
|
*/
|
||||||
|
public static String extractHsErrFileNameFromOutput(OutputAnalyzer output) {
|
||||||
|
output.shouldMatch("# A fatal error has been detected.*");
|
||||||
|
|
||||||
|
// extract hs-err file
|
||||||
|
String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1);
|
||||||
|
if (hs_err_file == null) {
|
||||||
|
throw new RuntimeException("Did not find hs-err file in output.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return hs_err_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the output of a java VM that crashed, extract the name of the hs-err file from the output,
|
||||||
|
* open that file and return its File.
|
||||||
|
*/
|
||||||
|
public static File openHsErrFileFromOutput(OutputAnalyzer output) {
|
||||||
|
String name = extractHsErrFileNameFromOutput(output);
|
||||||
|
File f = new File(name);
|
||||||
|
if (!f.exists()) {
|
||||||
|
throw new RuntimeException("Cannot find hs-err file at " + f.getAbsolutePath());
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user