mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
8302491: NoClassDefFoundError omits the original cause of an error
Reviewed-by: coleenp, dholmes
(cherry picked from commit 5685107579)
This commit is contained in:
committed by
Vitaly Provodin
parent
855076e436
commit
1a344b8ecd
@@ -2742,49 +2742,57 @@ void java_lang_Throwable::get_stack_trace_elements(int depth, Handle backtrace,
|
||||
}
|
||||
}
|
||||
|
||||
Handle java_lang_Throwable::get_cause_with_stack_trace(Handle throwable, TRAPS) {
|
||||
// Call to JVM to fill in the stack trace and clear declaringClassObject to
|
||||
// not keep classes alive in the stack trace.
|
||||
// call this: public StackTraceElement[] getStackTrace()
|
||||
Handle java_lang_Throwable::create_initialization_error(JavaThread* current, Handle throwable) {
|
||||
// Creates an ExceptionInInitializerError to be recorded as the initialization error when class initialization
|
||||
// failed due to the passed in 'throwable'. We cannot save 'throwable' directly due to issues with keeping alive
|
||||
// all objects referenced via its stacktrace. So instead we save a new EIIE instance, with the same message and
|
||||
// symbolic stacktrace of 'throwable'.
|
||||
assert(throwable.not_null(), "shouldn't be");
|
||||
|
||||
// Now create the message from the original exception and thread name.
|
||||
Symbol* message = java_lang_Throwable::detail_message(throwable());
|
||||
ResourceMark rm(current);
|
||||
stringStream st;
|
||||
st.print("Exception %s%s ", throwable()->klass()->name()->as_klass_external_name(),
|
||||
message == nullptr ? "" : ":");
|
||||
if (message == nullptr) {
|
||||
st.print("[in thread \"%s\"]", current->name());
|
||||
} else {
|
||||
st.print("%s [in thread \"%s\"]", message->as_C_string(), current->name());
|
||||
}
|
||||
|
||||
Symbol* exception_name = vmSymbols::java_lang_ExceptionInInitializerError();
|
||||
Handle init_error = Exceptions::new_exception(current, exception_name, st.as_string());
|
||||
// If new_exception returns a different exception while creating the exception,
|
||||
// abandon the attempt to save the initialization error and return null.
|
||||
if (init_error->klass()->name() != exception_name) {
|
||||
log_info(class, init)("Exception thrown while saving initialization exception %s",
|
||||
init_error->klass()->external_name());
|
||||
return Handle();
|
||||
}
|
||||
|
||||
// Call to java to fill in the stack trace and clear declaringClassObject to
|
||||
// not keep classes alive in the stack trace.
|
||||
// call this: public StackTraceElement[] getStackTrace()
|
||||
JavaValue result(T_ARRAY);
|
||||
JavaCalls::call_virtual(&result, throwable,
|
||||
vmClasses::Throwable_klass(),
|
||||
vmSymbols::getStackTrace_name(),
|
||||
vmSymbols::getStackTrace_signature(),
|
||||
CHECK_NH);
|
||||
Handle stack_trace(THREAD, result.get_oop());
|
||||
assert(stack_trace->is_objArray(), "Should be an array");
|
||||
|
||||
// Throw ExceptionInInitializerError as the cause with this exception in
|
||||
// the message and stack trace.
|
||||
|
||||
// Now create the message with the original exception and thread name.
|
||||
Symbol* message = java_lang_Throwable::detail_message(throwable());
|
||||
ResourceMark rm(THREAD);
|
||||
stringStream st;
|
||||
st.print("Exception %s%s ", throwable()->klass()->name()->as_klass_external_name(),
|
||||
message == nullptr ? "" : ":");
|
||||
if (message == nullptr) {
|
||||
st.print("[in thread \"%s\"]", THREAD->name());
|
||||
current);
|
||||
if (!current->has_pending_exception()){
|
||||
Handle stack_trace(current, result.get_oop());
|
||||
assert(stack_trace->is_objArray(), "Should be an array");
|
||||
java_lang_Throwable::set_stacktrace(init_error(), stack_trace());
|
||||
// Clear backtrace because the stacktrace should be used instead.
|
||||
set_backtrace(init_error(), nullptr);
|
||||
} else {
|
||||
st.print("%s [in thread \"%s\"]", message->as_C_string(), THREAD->name());
|
||||
log_info(class, init)("Exception thrown while getting stack trace for initialization exception %s",
|
||||
init_error->klass()->external_name());
|
||||
current->clear_pending_exception();
|
||||
}
|
||||
|
||||
Symbol* exception_name = vmSymbols::java_lang_ExceptionInInitializerError();
|
||||
Handle h_cause = Exceptions::new_exception(THREAD, exception_name, st.as_string());
|
||||
|
||||
// If new_exception returns a different exception while creating the exception, return null.
|
||||
if (h_cause->klass()->name() != exception_name) {
|
||||
log_info(class, init)("Exception thrown while saving initialization exception %s",
|
||||
h_cause->klass()->external_name());
|
||||
return Handle();
|
||||
}
|
||||
java_lang_Throwable::set_stacktrace(h_cause(), stack_trace());
|
||||
// Clear backtrace because the stacktrace should be used instead.
|
||||
set_backtrace(h_cause(), nullptr);
|
||||
return h_cause;
|
||||
return init_error;
|
||||
}
|
||||
|
||||
bool java_lang_Throwable::get_top_method_and_bci(oop throwable, Method** method, int* bci) {
|
||||
|
||||
@@ -618,7 +618,7 @@ class java_lang_Throwable: AllStatic {
|
||||
static void get_stack_trace_elements(int depth, Handle backtrace, objArrayHandle stack_trace, TRAPS);
|
||||
|
||||
// For recreating class initialization error exceptions.
|
||||
static Handle get_cause_with_stack_trace(Handle throwable, TRAPS);
|
||||
static Handle create_initialization_error(JavaThread* current, Handle throwable);
|
||||
|
||||
// Printing
|
||||
static void print(oop throwable, outputStream* st);
|
||||
|
||||
@@ -994,18 +994,18 @@ void InstanceKlass::add_initialization_error(JavaThread* current, Handle excepti
|
||||
// If the initialization error is OOM, this might not work, but if GC kicks in
|
||||
// this would be still be helpful.
|
||||
JavaThread* THREAD = current;
|
||||
Handle cause = java_lang_Throwable::get_cause_with_stack_trace(exception, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION || cause.is_null()) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
Handle init_error = java_lang_Throwable::create_initialization_error(current, exception);
|
||||
ResourceMark rm(THREAD);
|
||||
if (init_error.is_null()) {
|
||||
log_trace(class, init)("Initialization error is null for class %s", external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
MutexLocker ml(THREAD, ClassInitError_lock);
|
||||
OopHandle elem = OopHandle(Universe::vm_global(), cause());
|
||||
bool created = false;
|
||||
OopHandle elem = OopHandle(Universe::vm_global(), init_error());
|
||||
bool created;
|
||||
_initialization_error_table.put_if_absent(this, elem, &created);
|
||||
assert(created, "Initialization is single threaded");
|
||||
ResourceMark rm(THREAD);
|
||||
log_trace(class, init)("Initialization error added for class %s", external_name());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user