8308151: [JVMCI] capture JVMCI exceptions in hs-err

Reviewed-by: never
This commit is contained in:
Doug Simon 2023-05-24 07:15:12 +00:00
parent beb75e651f
commit 05c095cf39
12 changed files with 400 additions and 70 deletions

@ -152,6 +152,8 @@ class JVMCI : public AllStatic {
static void initialize_globals();
// Called to force initialization of the JVMCI compiler
// early in VM startup.
static void initialize_compiler(TRAPS);
// 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);
runtime = JVMCI::compiler_runtime(thread);
if (peerEnv->has_pending_exception()) {
peerEnv->describe_pending_exception(true);
peerEnv->describe_pending_exception(tty);
}
sl_handle = JVMCI::get_shared_library(sl_path, false);
if (sl_handle == nullptr) {
@ -2577,7 +2577,7 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb
HandleMark hm(thread);
JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerJVMCIEnv);
if (peerJVMCIEnv->has_pending_exception()) {
peerJVMCIEnv->describe_pending_exception(true);
peerJVMCIEnv->describe_pending_exception(tty);
}
char* sl_path;
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.
void JVMCIEnv::describe_pending_exception(bool clear) {
JavaThread* THREAD = JavaThread::current(); // For exception macros.
if (!is_hotspot()) {
JNIAccessMark jni(this, THREAD);
if (jni()->ExceptionCheck()) {
jthrowable ex = !clear ? jni()->ExceptionOccurred() : nullptr;
jni()->ExceptionDescribe();
if (ex != nullptr) {
jni()->Throw(ex);
// Prints a pending exception (if any) and its stack trace to st.
// Also partially logs the stack trace to the JVMCI event log.
void JVMCIEnv::describe_pending_exception(outputStream* st) {
ResourceMark rm;
char* stack_trace = nullptr;
if (pending_exception_as_string(nullptr, (const char**) &stack_trace)) {
st->print_raw_cr(stack_trace);
// Use up to half the lines of the JVMCI event log to
// 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 (HAS_PENDING_EXCEPTION) {
JVMCIRuntime::describe_pending_hotspot_exception(THREAD, clear);
if (last_line != nullptr) {
if (line > max_lines) {
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.
class ExceptionTranslation: public StackObj {
protected:
@ -771,10 +884,11 @@ const char* JVMCIEnv::as_utf8_string(JVMCIObject str) {
return java_lang_String::as_utf8_string(HotSpotJVMCI::resolve(str));
} else {
JNIAccessMark jni(this);
int length = jni()->GetStringLength(str.as_jstring());
int utf8_length = jni()->GetStringUTFLength(str.as_jstring());
jstring jstr = str.as_jstring();
int length = jni()->GetStringLength(jstr);
int utf8_length = jni()->GetStringUTFLength(jstr);
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;
}
}
@ -904,7 +1018,7 @@ void JVMCIEnv::call_HotSpotJVMCIRuntime_shutdown (JVMCIObject runtime) {
if (has_pending_exception()) {
// This should never happen as HotSpotJVMCIRuntime.shutdown() should
// 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) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
if (is_hotspot()) {

@ -258,10 +258,16 @@ public:
// 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);
// 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 `clear` is false, the pending exception will remain pending upon return.
void describe_pending_exception(bool clear);
void describe_pending_exception(outputStream* st);
// 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);
@ -342,8 +348,6 @@ public:
JVMCIObject call_JVMCI_getRuntime(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);
jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier);

@ -72,7 +72,7 @@ class JVMCIEnv;
#define JVMCI_CATCH \
JVMCIENV); if (JVMCI_HAS_PENDING_EXCEPTION) { \
JVMCIENV->describe_pending_exception(true); \
JVMCIENV->describe_pending_exception(tty); \
ShouldNotReachHere(); \
} (void)(0

@ -206,7 +206,7 @@
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(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)) \
end_class \
start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \

@ -35,6 +35,7 @@
#include "jvmci/jvmciRuntime.hpp"
#include "jvmci/metadataHandles.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.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) {
Handle exception(THREAD, PENDING_EXCEPTION);
const char* exception_file = THREAD->exception_file();
int exception_line = THREAD->exception_line();
CLEAR_PENDING_EXCEPTION;
java_lang_Throwable::print_stack_trace(exception, tty);
// Clear and ignore any exceptions raised during printing
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
tty->print_raw_cr(message);
if (JVMCIENV != nullptr) {
JVMCIENV->describe_pending_exception(true);
JVMCIENV->describe_pending_exception(tty);
} else {
describe_pending_hotspot_exception(THREAD, true);
describe_pending_hotspot_exception(THREAD);
}
} else {
// Allow error reporting thread to print the stack trace.
// Allow error reporting thread time to print the stack trace.
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.
static bool after_compiler_upcall(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, const methodHandle& method, const char* function) {
if (JVMCIENV->has_pending_exception()) {
ResourceMark rm;
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) {
failure_reason = "uncaught exception";
reason_on_C_heap = false;
}
JVMCI_event_1("%s", failure_reason);
Log(jit, compilation) log;
if (log.is_info()) {
ResourceMark rm;
log.info("%s while compiling %s", failure_reason, method->name_and_sig_as_C_string());
JVMCIENV->describe_pending_exception(true);
} else {
JVMCIENV->clear_pending_exception();
if (pending_stack_trace != nullptr) {
LogStream ls(log.info());
ls.print_raw_cr(pending_stack_trace);
}
}
JVMCICompileState* compile_state = JVMCIENV->compile_state();
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,
(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")) {
return;
}

@ -469,7 +469,7 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
// Reports an unexpected exception and exits the VM with a fatal error.
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); \
if (HAS_PENDING_EXCEPTION) { \

@ -94,8 +94,8 @@
template(runtime_signature, "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;") \
template(getCompiler_name, "getCompiler") \
template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \
template(callToString_name, "callToString") \
template(callToString_signature, "(Ljava/lang/Object;)Ljava/lang/String;") \
template(exceptionToString_name, "exceptionToString") \
template(exceptionToString_signature, "(Ljava/lang/Throwable;ZZ)[Ljava/lang/String;") \
template(postTranslation_name, "postTranslation") \
template(getName_name, "getName") \
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 java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Serializable;
@ -39,6 +40,7 @@ import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
@ -198,8 +200,19 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
}
@VMEntryPoint
static String callToString(Object o) {
return o.toString();
static String[] exceptionToString(Throwable o, boolean toString, boolean stackTrace) {
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;
}
}