From 8879c78d62e3c1f325def56d131f62c479bfdaa9 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 24 Oct 2023 13:32:26 +0000 Subject: [PATCH] 8317689: [JVMCI] include error message when CreateJavaVM in libgraal fails Reviewed-by: phofer, thartmann, never --- src/hotspot/share/compiler/compileBroker.cpp | 4 +++- src/hotspot/share/jvmci/jvmciEnv.cpp | 21 +++++++++++++------- src/hotspot/share/jvmci/jvmciEnv.hpp | 7 +++++++ src/hotspot/share/jvmci/jvmciRuntime.cpp | 6 ++++-- src/hotspot/share/jvmci/jvmciRuntime.hpp | 6 ++++-- src/hotspot/share/prims/whitebox.cpp | 2 +- 6 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index f265271857d..22a9eb4dcaa 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2211,7 +2211,9 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { } else { JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__); if (env.init_error() != JNI_OK) { - failure_reason = os::strdup(err_msg("Error attaching to libjvmci (err: %d)", env.init_error()), mtJVMCI); + const char* msg = env.init_error_msg(); + failure_reason = os::strdup(err_msg("Error attaching to libjvmci (err: %d, %s)", + env.init_error(), msg == nullptr ? "unknown" : msg), mtJVMCI); bool reason_on_C_heap = true; // In case of JNI_ENOMEM, there's a good chance a subsequent attempt to create libjvmci or attach to it // might succeed. Other errors most likely indicate a non-recoverable error in the JVMCI runtime. diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index bab3de8c335..24af7715a5b 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -147,13 +147,14 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { _is_hotspot = false; _runtime = JVMCI::compiler_runtime(thread); - _env = _runtime->init_shared_library_javavm(&_init_error); + _env = _runtime->init_shared_library_javavm(&_init_error, &_init_error_msg); if (_env != nullptr) { // Creating the JVMCI shared library VM also attaches the current thread _detach_on_close = true; } else if (_init_error != JNI_OK) { // Caller creating this JVMCIEnv must handle the error. - JVMCI_event_1("[%s:%d] Error creating libjvmci (err: %d)", _file, _line, _init_error); + JVMCI_event_1("[%s:%d] Error creating libjvmci (err: %d, %s)", _file, _line, + _init_error, _init_error_msg == nullptr ? "unknown" : _init_error_msg); return; } else { _runtime->GetEnv(thread, (void**)&parent_env, JNI_VERSION_1_2); @@ -195,17 +196,17 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { } JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line): - _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _compile_state(compile_state) { + _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _init_error_msg(nullptr), _compile_state(compile_state) { init_env_mode_runtime(thread, nullptr); } JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): - _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _compile_state(nullptr) { + _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _init_error_msg(nullptr), _compile_state(nullptr) { init_env_mode_runtime(thread, nullptr); } JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line): - _throw_to_caller(true), _file(file), _line(line), _init_error(JNI_OK), _compile_state(nullptr) { + _throw_to_caller(true), _file(file), _line(line), _init_error(JNI_OK), _init_error_msg(nullptr), _compile_state(nullptr) { assert(parent_env != nullptr, "npe"); init_env_mode_runtime(thread, parent_env); assert(_env == nullptr || parent_env == _env, "mismatched JNIEnvironment"); @@ -218,6 +219,7 @@ void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int l _file = file; _line = line; _init_error = JNI_OK; + _init_error_msg = nullptr; if (is_hotspot) { _env = nullptr; _pop_frame_on_close = false; @@ -237,7 +239,8 @@ void JVMCIEnv::check_init(JVMCI_TRAPS) { if (_init_error == JNI_ENOMEM) { JVMCI_THROW_MSG(OutOfMemoryError, "JNI_ENOMEM creating or attaching to libjvmci"); } - JVMCI_THROW_MSG(InternalError, err_msg("Error creating or attaching to libjvmci (err: %d)", _init_error)); + JVMCI_THROW_MSG(InternalError, err_msg("Error creating or attaching to libjvmci (err: %d, description: %s)", + _init_error, _init_error_msg == nullptr ? "unknown" : _init_error_msg)); } void JVMCIEnv::check_init(TRAPS) { @@ -247,7 +250,8 @@ void JVMCIEnv::check_init(TRAPS) { if (_init_error == JNI_ENOMEM) { THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "JNI_ENOMEM creating or attaching to libjvmci"); } - THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), err_msg("Error creating or attaching to libjvmci (err: %d)", _init_error)); + THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), err_msg("Error creating or attaching to libjvmci (err: %d, description: %s)", + _init_error, _init_error_msg == nullptr ? "unknown" : _init_error_msg)); } // Prints a pending exception (if any) and its stack trace to st. @@ -572,6 +576,9 @@ jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer } JVMCIEnv::~JVMCIEnv() { + if (_init_error_msg != nullptr) { + os::free((void*) _init_error_msg); + } if (_init_error != JNI_OK) { return; } diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index 59600b97fe1..ace0cc53352 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -172,6 +172,7 @@ class JVMCIEnv : public ResourceObj { int _init_error; // JNI code returned when creating or attaching to a libjvmci isolate. // If not JNI_OK, the JVMCIEnv is invalid and should not be used apart from // calling init_error(). + const char* _init_error_msg; // Message for _init_error if available. C heap allocated. // 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`. @@ -217,6 +218,12 @@ public: return _init_error; } + // Gets a message describing a non-zero init_error(). + // Valid as long as this JVMCIEnv is valid. + const char* init_error_msg() { + return _init_error_msg; + } + // Checks the value of init_error() and throws an exception in `JVMCI_TRAPS` // (which must not be this) if it is not JNI_OK. void check_init(JVMCI_TRAPS); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 68177fa8acd..226c4f5dea1 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1253,7 +1253,7 @@ bool JVMCIRuntime::detach_thread(JavaThread* thread, const char* reason, bool ca return destroyed_javavm; } -JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err) { +JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err, const char** err_msg) { MutexLocker locker(_lock); JavaVM* javaVM = _shared_library_javavm; if (javaVM == nullptr) { @@ -1280,7 +1280,7 @@ JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err) { JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.ignoreUnrecognized = JNI_TRUE; - JavaVMOption options[5]; + JavaVMOption options[6]; jlong javaVM_id = 0; // Protocol: JVMCI shared library JavaVM should support a non-standard "_javavm_id" @@ -1297,6 +1297,8 @@ JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err) { options[3].extraInfo = (void*) _fatal; options[4].optionString = (char*) "_fatal_log"; options[4].extraInfo = (void*) _fatal_log; + options[5].optionString = (char*) "_createvm_errorstr"; + options[5].extraInfo = (void*) err_msg; vm_args.version = JNI_VERSION_1_2; vm_args.options = options; diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index a3f464cd724..d3898be4ce0 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -280,8 +280,10 @@ class JVMCIRuntime: public CHeapObj { // If the JavaVM was created by this call, then the thread-local JNI // interface pointer for the JavaVM is returned otherwise null is returned. // If this method tried to create the JavaVM but failed, the error code returned - // by JNI_CreateJavaVM is returned in create_JavaVM_err. - JNIEnv* init_shared_library_javavm(int* create_JavaVM_err); + // by JNI_CreateJavaVM is returned in create_JavaVM_err and, if available, an + // error message is malloc'ed and assigned to err_msg. The caller is responsible + // for freeing err_msg. + JNIEnv* init_shared_library_javavm(int* create_JavaVM_err, const char** err_msg); // Determines if the JVMCI shared library JavaVM exists for this runtime. bool has_shared_library_javavm() { return _shared_library_javavm != nullptr; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index e86217f8de6..e0f1b071c30 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -381,7 +381,7 @@ WB_ENTRY(jboolean, WB_IsGCSupportedByJVMCICompiler(JNIEnv* env, jobject o, jint if (EnableJVMCI) { // Enter the JVMCI env that will be used by the CompileBroker. JVMCIEnv jvmciEnv(thread, __FILE__, __LINE__); - return jvmciEnv.runtime()->is_gc_supported(&jvmciEnv, (CollectedHeap::Name)name); + return jvmciEnv.init_error() == JNI_OK && jvmciEnv.runtime()->is_gc_supported(&jvmciEnv, (CollectedHeap::Name)name); } #endif return false;