Merge
This commit is contained in:
commit
c6c828fa6e
1
.hgtags
1
.hgtags
@ -612,4 +612,5 @@ decd3d2953b640f1043ee76953ff89238bff92e8 jdk-14+31
|
||||
b97c1773ccafae4a8c16cc6aedb10b2a4f9a07ed jdk-15+5
|
||||
2776da28515e087cc8849acf1e131a65ea7e77b6 jdk-14+32
|
||||
ef7d53b4fccd4a0501b17d974e84f37aa99fa813 jdk-15+6
|
||||
f728b6c7f4910d6bd6070cb4dde8393f4ba95113 jdk-14+33
|
||||
e2bc57500c1b785837982f7ce8af6751387ed73b jdk-15+7
|
||||
|
@ -463,6 +463,7 @@ void AOTCodeHeap::link_shared_runtime_symbols() {
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_virtual_entry", address, SharedRuntime::get_resolve_virtual_call_stub());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_opt_virtual_entry", address, SharedRuntime::get_resolve_opt_virtual_call_stub());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_unpack", address, SharedRuntime::deopt_blob()->unpack());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_unpack_with_exception_in_tls", address, SharedRuntime::deopt_blob()->unpack_with_exception_in_tls());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_uncommon_trap", address, SharedRuntime::deopt_blob()->uncommon_trap());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_ic_miss_stub", address, SharedRuntime::get_ic_miss_stub());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_handle_wrong_method_stub", address, SharedRuntime::get_handle_wrong_method_stub());
|
||||
|
@ -45,6 +45,7 @@ class CompilerToVM {
|
||||
static address SharedRuntime_ic_miss_stub;
|
||||
static address SharedRuntime_handle_wrong_method_stub;
|
||||
static address SharedRuntime_deopt_blob_unpack;
|
||||
static address SharedRuntime_deopt_blob_unpack_with_exception_in_tls;
|
||||
static address SharedRuntime_deopt_blob_uncommon_trap;
|
||||
|
||||
static size_t ThreadLocalAllocBuffer_alignment_reserve;
|
||||
|
@ -44,6 +44,7 @@ int CompilerToVM::Data::Method_extra_stack_entries;
|
||||
address CompilerToVM::Data::SharedRuntime_ic_miss_stub;
|
||||
address CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub;
|
||||
address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack;
|
||||
address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack_with_exception_in_tls;
|
||||
address CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap;
|
||||
|
||||
size_t CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve;
|
||||
@ -97,6 +98,7 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) {
|
||||
SharedRuntime_ic_miss_stub = SharedRuntime::get_ic_miss_stub();
|
||||
SharedRuntime_handle_wrong_method_stub = SharedRuntime::get_handle_wrong_method_stub();
|
||||
SharedRuntime_deopt_blob_unpack = SharedRuntime::deopt_blob()->unpack();
|
||||
SharedRuntime_deopt_blob_unpack_with_exception_in_tls = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
||||
SharedRuntime_deopt_blob_uncommon_trap = SharedRuntime::deopt_blob()->uncommon_trap();
|
||||
|
||||
ThreadLocalAllocBuffer_alignment_reserve = ThreadLocalAllocBuffer::alignment_reserve();
|
||||
|
@ -454,22 +454,31 @@ JRT_LEAF(jboolean, JVMCIRuntime::object_notifyAll(JavaThread *thread, oopDesc* o
|
||||
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, JVMCIRuntime::throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message))
|
||||
JRT_BLOCK_ENTRY(int, JVMCIRuntime::throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message))
|
||||
JRT_BLOCK;
|
||||
TempNewSymbol symbol = SymbolTable::new_symbol(exception);
|
||||
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);
|
||||
JRT_BLOCK_END;
|
||||
return caller_is_deopted();
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, JVMCIRuntime::throw_klass_external_name_exception(JavaThread* thread, const char* exception, Klass* klass))
|
||||
JRT_BLOCK_ENTRY(int, JVMCIRuntime::throw_klass_external_name_exception(JavaThread* thread, const char* exception, Klass* klass))
|
||||
JRT_BLOCK;
|
||||
ResourceMark rm(thread);
|
||||
TempNewSymbol symbol = SymbolTable::new_symbol(exception);
|
||||
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, klass->external_name());
|
||||
JRT_BLOCK_END;
|
||||
return caller_is_deopted();
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, JVMCIRuntime::throw_class_cast_exception(JavaThread* thread, const char* exception, Klass* caster_klass, Klass* target_klass))
|
||||
JRT_BLOCK_ENTRY(int, JVMCIRuntime::throw_class_cast_exception(JavaThread* thread, const char* exception, Klass* caster_klass, Klass* target_klass))
|
||||
JRT_BLOCK;
|
||||
ResourceMark rm(thread);
|
||||
const char* message = SharedRuntime::generate_class_cast_message(caster_klass, target_klass);
|
||||
TempNewSymbol symbol = SymbolTable::new_symbol(exception);
|
||||
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);
|
||||
JRT_BLOCK_END;
|
||||
return caller_is_deopted();
|
||||
JRT_END
|
||||
|
||||
JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, bool as_string, bool newline))
|
||||
|
@ -332,10 +332,10 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
|
||||
static jboolean validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child);
|
||||
|
||||
// used to throw exceptions from compiled JVMCI code
|
||||
static void throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message);
|
||||
static int throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message);
|
||||
// helper methods to throw exception with complex messages
|
||||
static void throw_klass_external_name_exception(JavaThread* thread, const char* exception, Klass* klass);
|
||||
static void throw_class_cast_exception(JavaThread* thread, const char* exception, Klass* caster_klass, Klass* target_klass);
|
||||
static int throw_klass_external_name_exception(JavaThread* thread, const char* exception, Klass* klass);
|
||||
static int throw_class_cast_exception(JavaThread* thread, const char* exception, Klass* caster_klass, Klass* target_klass);
|
||||
|
||||
// Test only function
|
||||
static jint test_deoptimize_call_int(JavaThread* thread, int value);
|
||||
|
@ -48,6 +48,7 @@
|
||||
static_field(CompilerToVM::Data, SharedRuntime_ic_miss_stub, address) \
|
||||
static_field(CompilerToVM::Data, SharedRuntime_handle_wrong_method_stub, address) \
|
||||
static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_unpack, address) \
|
||||
static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_unpack_with_exception_in_tls, address) \
|
||||
static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_uncommon_trap, address) \
|
||||
\
|
||||
static_field(CompilerToVM::Data, ThreadLocalAllocBuffer_alignment_reserve, size_t) \
|
||||
|
@ -36,15 +36,16 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
|
||||
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
|
||||
import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
|
||||
import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
|
||||
|
||||
/**
|
||||
* A format-agnostic container class that holds various components of a binary.
|
||||
@ -145,6 +146,7 @@ public final class BinaryContainer implements SymbolTable {
|
||||
private static final String[][] map = {
|
||||
{"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", "_aot_deopt_blob_unpack"},
|
||||
{"CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", "_aot_deopt_blob_uncommon_trap"},
|
||||
{"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack_with_exception_in_tls", "_aot_deopt_blob_unpack_with_exception_in_tls"},
|
||||
{"CompilerToVM::Data::SharedRuntime_ic_miss_stub", "_aot_ic_miss_stub"},
|
||||
{"CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", "_aot_handle_wrong_method_stub"},
|
||||
{"SharedRuntime::exception_handler_for_return_address", "_aot_exception_handler_for_return_address"},
|
||||
|
@ -51,7 +51,14 @@ public abstract class SubprocessTest extends GraalCompilerTest {
|
||||
vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS);
|
||||
vmArgs.add("-D" + recursionPropName + "=true");
|
||||
configSubprocess(vmArgs);
|
||||
boolean verbose = Boolean.getBoolean(getClass().getSimpleName() + ".verbose");
|
||||
if (verbose) {
|
||||
System.err.println(String.join(" ", vmArgs));
|
||||
}
|
||||
SubprocessUtil.Subprocess proc = java(vmArgs, "com.oracle.mxtool.junit.MxJUnitWrapper", getClass().getName());
|
||||
if (verbose) {
|
||||
System.err.println(proc.output);
|
||||
}
|
||||
assertTrue(proc.exitCode == 0, proc.toString() + " failed with exit code " + proc.exitCode);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import org.graalvm.compiler.nodes.ConstantNode;
|
||||
import org.graalvm.compiler.nodes.FrameState;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.spi.NodeValueMap;
|
||||
import org.graalvm.compiler.nodes.spi.NodeWithState;
|
||||
import org.graalvm.compiler.nodes.util.GraphUtil;
|
||||
import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
|
||||
import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode;
|
||||
@ -80,7 +81,7 @@ public class DebugInfoBuilder {
|
||||
|
||||
protected final Queue<VirtualObjectNode> pendingVirtualObjects = new ArrayDeque<>();
|
||||
|
||||
public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) {
|
||||
public LIRFrameState build(NodeWithState node, FrameState topState, LabelRef exceptionEdge) {
|
||||
assert virtualObjects.size() == 0;
|
||||
assert objectStates.size() == 0;
|
||||
assert pendingVirtualObjects.size() == 0;
|
||||
@ -100,7 +101,8 @@ public class DebugInfoBuilder {
|
||||
current = current.outerFrameState();
|
||||
} while (current != null);
|
||||
|
||||
BytecodeFrame frame = computeFrameForState(topState);
|
||||
assert verifyFrameState(node, topState);
|
||||
BytecodeFrame frame = computeFrameForState(node, topState);
|
||||
|
||||
VirtualObject[] virtualObjectsArray = null;
|
||||
if (virtualObjects.size() != 0) {
|
||||
@ -223,7 +225,18 @@ public class DebugInfoBuilder {
|
||||
return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge);
|
||||
}
|
||||
|
||||
protected BytecodeFrame computeFrameForState(FrameState state) {
|
||||
/**
|
||||
* Perform platform dependent verification of the FrameState.
|
||||
*
|
||||
* @param node the node using the state
|
||||
* @param topState the state
|
||||
* @return true if the validation succeeded
|
||||
*/
|
||||
protected boolean verifyFrameState(NodeWithState node, FrameState topState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected BytecodeFrame computeFrameForState(NodeWithState node, FrameState state) {
|
||||
try {
|
||||
assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI;
|
||||
assert state.bci != BytecodeFrame.UNKNOWN_BCI;
|
||||
@ -249,7 +262,7 @@ public class DebugInfoBuilder {
|
||||
|
||||
BytecodeFrame caller = null;
|
||||
if (state.outerFrameState() != null) {
|
||||
caller = computeFrameForState(state.outerFrameState());
|
||||
caller = computeFrameForState(node, state.outerFrameState());
|
||||
}
|
||||
|
||||
if (!state.canProduceBytecodeFrame()) {
|
||||
|
@ -104,6 +104,7 @@ import org.graalvm.compiler.nodes.extended.SwitchNode;
|
||||
import org.graalvm.compiler.nodes.spi.LIRLowerable;
|
||||
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
||||
import org.graalvm.compiler.nodes.spi.NodeValueMap;
|
||||
import org.graalvm.compiler.nodes.spi.NodeWithState;
|
||||
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
@ -735,26 +736,26 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
|
||||
if (!deopt.canDeoptimize()) {
|
||||
return null;
|
||||
}
|
||||
return stateFor(getFrameState(deopt));
|
||||
return stateFor(deopt, getFrameState(deopt));
|
||||
}
|
||||
|
||||
public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
|
||||
if (!deopt.canDeoptimize()) {
|
||||
return null;
|
||||
}
|
||||
return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
|
||||
return stateForWithExceptionEdge(deopt, getFrameState(deopt), exceptionEdge);
|
||||
}
|
||||
|
||||
public LIRFrameState stateFor(FrameState state) {
|
||||
return stateForWithExceptionEdge(state, null);
|
||||
public LIRFrameState stateFor(NodeWithState deopt, FrameState state) {
|
||||
return stateForWithExceptionEdge(deopt, state, null);
|
||||
}
|
||||
|
||||
public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
|
||||
public LIRFrameState stateForWithExceptionEdge(NodeWithState deopt, FrameState state, LabelRef exceptionEdge) {
|
||||
if (gen.needOnlyOopMaps()) {
|
||||
return new LIRFrameState(null, null, null);
|
||||
}
|
||||
assert state != null;
|
||||
return getDebugInfoBuilder().build(state, exceptionEdge);
|
||||
assert state != null : deopt;
|
||||
return getDebugInfoBuilder().build(deopt, state, exceptionEdge);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -765,7 +766,7 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
|
||||
|
||||
@Override
|
||||
public void visitFullInfopointNode(FullInfopointNode i) {
|
||||
append(new FullInfopointOp(stateFor(i.getState()), i.getReason()));
|
||||
append(new FullInfopointOp(stateFor(i, i.getState()), i.getReason()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -390,7 +390,7 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
|
||||
AArch64Call.directCall(crb, masm, linkage, helper, null);
|
||||
}
|
||||
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
||||
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
|
||||
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK);
|
||||
masm.adr(lr, 0); // Warning: the argument is an offset from the instruction!
|
||||
AArch64Call.directJmp(crb, masm, linkage);
|
||||
} else {
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.aarch64;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
@ -47,6 +47,6 @@ public class AArch64HotSpotDeoptimizeCallerOp extends AArch64HotSpotEpilogueOp {
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
leaveFrame(crb, masm, /* emitSafepoint */false, false);
|
||||
AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
|
||||
AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP));
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.aarch64;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.lir.LIRFrameState;
|
||||
@ -49,7 +49,7 @@ public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements Blo
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
|
||||
AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), scratch.getRegister(), info, null);
|
||||
AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP), scratch.getRegister(), info, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.aarch64;
|
||||
|
||||
import static jdk.vm.ci.aarch64.AArch64.lr;
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS;
|
||||
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.lir.LIRInstructionClass;
|
||||
import org.graalvm.compiler.lir.Opcode;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Call;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
||||
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
|
||||
/**
|
||||
* Removes the current frame and tail calls the uncommon trap routine.
|
||||
*/
|
||||
@Opcode("DEOPT_WITH_EXCEPTION_IN_CALLER")
|
||||
public class AArch64HotSpotDeoptimizeWithExceptionCallerOp extends AArch64HotSpotEpilogueOp {
|
||||
public static final LIRInstructionClass<AArch64HotSpotDeoptimizeWithExceptionCallerOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeWithExceptionCallerOp.class);
|
||||
|
||||
@Use(OperandFlag.REG) private Value exception;
|
||||
|
||||
public AArch64HotSpotDeoptimizeWithExceptionCallerOp(GraalHotSpotVMConfig config, Value exception, Register thread) {
|
||||
super(TYPE, config, thread);
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
Register exc = asRegister(exception);
|
||||
|
||||
leaveFrame(crb, masm, /* emitSafepoint */false, false);
|
||||
|
||||
// Save exception oop in TLS
|
||||
masm.str(64, exc, masm.makeAddress(thread, config.threadExceptionOopOffset, 8));
|
||||
// Store original return address in TLS
|
||||
masm.str(64, lr, masm.makeAddress(thread, config.threadExceptionPcOffset, 8));
|
||||
|
||||
AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS));
|
||||
}
|
||||
}
|
@ -53,8 +53,8 @@ import jdk.vm.ci.code.RegisterValue;
|
||||
*/
|
||||
abstract class AArch64HotSpotEpilogueOp extends AArch64BlockEndOp {
|
||||
|
||||
private final GraalHotSpotVMConfig config;
|
||||
private final Register thread;
|
||||
protected final GraalHotSpotVMConfig config;
|
||||
protected final Register thread;
|
||||
|
||||
protected AArch64HotSpotEpilogueOp(LIRInstructionClass<? extends AArch64HotSpotEpilogueOp> c, GraalHotSpotVMConfig config, Register thread) {
|
||||
super(c);
|
||||
|
@ -399,6 +399,12 @@ public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements H
|
||||
append(new AArch64HotSpotDeoptimizeCallerOp(config));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitDeoptimizeWithExceptionInCaller(Value exception) {
|
||||
Register thread = getProviders().getRegisters().getThreadRegister();
|
||||
append(new AArch64HotSpotDeoptimizeWithExceptionCallerOp(config, exception, thread));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
|
||||
moveDeoptValuesToThread(actionAndReason, failedSpeculation);
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.amd64;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.lir.LIRFrameState;
|
||||
@ -48,6 +48,6 @@ final class AMD64DeoptimizeOp extends AMD64BlockEndOp implements BlockEndOp {
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
|
||||
AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, false, info);
|
||||
AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP), null, false, info);
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend implements LIRGenera
|
||||
crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
|
||||
AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
|
||||
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
||||
AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
|
||||
AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, false, null);
|
||||
} else {
|
||||
// No need to emit the stubs for entries back into the method since
|
||||
// it has no calls that can cause such "return" entries
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.amd64;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.lir.LIRInstructionClass;
|
||||
@ -47,6 +47,6 @@ final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueBlockEndO
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
|
||||
leaveFrameAndRestoreRbp(crb, masm);
|
||||
AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
|
||||
AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.amd64;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.lir.LIRInstructionClass;
|
||||
import org.graalvm.compiler.lir.Opcode;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Call;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
|
||||
/**
|
||||
* Removes the current frame and tail calls the uncommon trap routine.
|
||||
*/
|
||||
@Opcode("DEOPT_WITH_EXCEPTION_IN_CALLER")
|
||||
final class AMD64HotSpotDeoptimizeWithExceptionCallerOp extends AMD64HotSpotEpilogueBlockEndOp {
|
||||
|
||||
public static final LIRInstructionClass<AMD64HotSpotDeoptimizeWithExceptionCallerOp> TYPE = LIRInstructionClass.create(AMD64HotSpotDeoptimizeWithExceptionCallerOp.class);
|
||||
private final GraalHotSpotVMConfig config;
|
||||
@Use(OperandFlag.REG) private Value exception;
|
||||
|
||||
protected AMD64HotSpotDeoptimizeWithExceptionCallerOp(GraalHotSpotVMConfig config, Value exception) {
|
||||
super(TYPE);
|
||||
this.config = config;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
|
||||
Register stackPointer = crb.frameMap.getRegisterConfig().getFrameRegister();
|
||||
Register exc = asRegister(exception);
|
||||
|
||||
leaveFrameAndRestoreRbp(crb, masm);
|
||||
|
||||
// Save exception oop in TLS
|
||||
masm.movq(new AMD64Address(AMD64.r15, config.threadExceptionOopOffset), exc);
|
||||
// Get return address and store it into TLS
|
||||
masm.movq(exc, new AMD64Address(stackPointer, 0));
|
||||
masm.movq(new AMD64Address(AMD64.r15, config.threadExceptionPcOffset), exc);
|
||||
|
||||
// Remove return address.
|
||||
masm.addq(stackPointer, crb.target.arch.getReturnAddressSize());
|
||||
AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS));
|
||||
}
|
||||
}
|
@ -544,6 +544,11 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
|
||||
append(new AMD64HotSpotDeoptimizeCallerOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitDeoptimizeWithExceptionInCaller(Value exception) {
|
||||
append(new AMD64HotSpotDeoptimizeWithExceptionCallerOp(config, exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRegisterAllocation() {
|
||||
super.beforeRegisterAllocation();
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.sparc;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
|
||||
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
@ -62,6 +62,6 @@ final class SPARCDeoptimizeOp extends SPARCBlockEndOp {
|
||||
// [Deopt Handler Code]
|
||||
// 0xffffffff749bb60c: call 0xffffffff748da540 ; {runtime_call}
|
||||
// 0xffffffff749bb610: nop
|
||||
SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
|
||||
SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP), null, info);
|
||||
}
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ public class SPARCHotSpotBackend extends HotSpotHostBackend implements LIRGenera
|
||||
crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
|
||||
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
|
||||
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
||||
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null);
|
||||
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, null);
|
||||
} else {
|
||||
// No need to emit the stubs for entries back into the method since
|
||||
// it has no calls that can cause such "return" entries
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.sparc;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
|
||||
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
|
||||
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
|
||||
@ -59,7 +59,7 @@ final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp {
|
||||
|
||||
try (ScratchRegister sc = masm.getScratchRegister()) {
|
||||
Register scratch = sc.getRegister();
|
||||
SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
|
||||
SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP));
|
||||
}
|
||||
|
||||
// frameContext.leave(crb);
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.sparc;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS;
|
||||
|
||||
import org.graalvm.compiler.asm.sparc.SPARCAddress;
|
||||
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.lir.LIRInstructionClass;
|
||||
import org.graalvm.compiler.lir.Opcode;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
||||
import org.graalvm.compiler.lir.sparc.SPARCCall;
|
||||
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import jdk.vm.ci.sparc.SPARC;
|
||||
|
||||
/**
|
||||
* Removes the current frame and tail calls the uncommon trap routine.
|
||||
*/
|
||||
@Opcode("DEOPT_WITH_EXCEPTION_IN_CALLER")
|
||||
final class SPARCHotSpotDeoptimizeWithExceptionCallerOp extends SPARCHotSpotEpilogueOp {
|
||||
public static final LIRInstructionClass<SPARCHotSpotDeoptimizeWithExceptionCallerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeWithExceptionCallerOp.class);
|
||||
public static final SizeEstimate SIZE = SizeEstimate.create(32);
|
||||
|
||||
private final GraalHotSpotVMConfig config;
|
||||
private final Register thread;
|
||||
@Use(OperandFlag.REG) private Value exception;
|
||||
|
||||
protected SPARCHotSpotDeoptimizeWithExceptionCallerOp(GraalHotSpotVMConfig config, Value exception, Register thread) {
|
||||
super(TYPE, SIZE);
|
||||
this.config = config;
|
||||
this.exception = exception;
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
|
||||
Register exc = asRegister(exception);
|
||||
|
||||
// Save exception oop in TLS
|
||||
masm.stx(exc, new SPARCAddress(thread, config.threadExceptionOopOffset));
|
||||
// Store original return address in TLS
|
||||
masm.stx(SPARC.i7, new SPARCAddress(thread, config.threadExceptionPcOffset));
|
||||
|
||||
leaveFrame(crb);
|
||||
|
||||
try (SPARCMacroAssembler.ScratchRegister sc = masm.getScratchRegister()) {
|
||||
Register scratch = sc.getRegister();
|
||||
SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS));
|
||||
}
|
||||
}
|
||||
}
|
@ -238,6 +238,12 @@ public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSp
|
||||
append(new SPARCHotSpotDeoptimizeCallerOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitDeoptimizeWithExceptionInCaller(Value exception) {
|
||||
Register thread = getProviders().getRegisters().getThreadRegister();
|
||||
append(new SPARCHotSpotDeoptimizeWithExceptionCallerOp(config, exception, thread));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
|
||||
ValueKind<?> kind = newValue.getValueKind();
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.test;
|
||||
|
||||
import static org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode.CheckAll;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.graalvm.compiler.core.test.SubprocessTest;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
import org.graalvm.compiler.hotspot.stubs.CreateExceptionStub;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* This test exercises the deoptimization in the BytecodeExceptioNode foreign call path.
|
||||
*/
|
||||
public class HotSpotDeoptExplicitExceptions extends SubprocessTest {
|
||||
|
||||
@Override
|
||||
protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
|
||||
return super.editGraphBuilderConfiguration(conf).withBytecodeExceptionMode(CheckAll);
|
||||
}
|
||||
|
||||
static String nullCheckSnippet(Object o) {
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
static int divByZeroSnippet(int x, int y) {
|
||||
return x / y;
|
||||
}
|
||||
|
||||
static String classCastSnippet(Object o) {
|
||||
return (String) o;
|
||||
}
|
||||
|
||||
void testBody() {
|
||||
test("nullCheckSnippet", (Object) null);
|
||||
test("divByZeroSnippet", 1, 0);
|
||||
test("classCastSnippet", Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configSubprocess(List<String> vmArgs) {
|
||||
vmArgs.add("-Dgraal.HotSpotDeoptExplicitExceptions=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explicitExceptions() throws IOException, InterruptedException {
|
||||
Assume.assumeTrue("required entry point is missing", ((HotSpotBackend) getBackend()).getRuntime().getVMConfig().deoptBlobUnpackWithExceptionInTLS != 0);
|
||||
if (!CreateExceptionStub.Options.HotSpotDeoptExplicitExceptions.getValue(getInitialOptions())) {
|
||||
launchSubprocess(this::testBody);
|
||||
} else {
|
||||
testBody();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.test;
|
||||
|
||||
import static org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode.CheckAll;
|
||||
|
||||
import org.graalvm.compiler.core.phases.HighTier;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotNodePlugin;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.tiers.Suites;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/**
|
||||
* This test exercises the FrameState used for deoptimization in the JVMTI post_on_exceptions path.
|
||||
*/
|
||||
public class HotSpotDeoptPostExceptions extends GraalCompilerTest {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("try")
|
||||
protected Suites createSuites(OptionValues options) {
|
||||
return super.createSuites(new OptionValues(options, HighTier.Options.Inline, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
|
||||
return InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
|
||||
return super.editGraphBuilderConfiguration(conf).withBytecodeExceptionMode(CheckAll);
|
||||
}
|
||||
|
||||
static String snippet(Object o) {
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost() {
|
||||
OptionValues options = new OptionValues(getInitialOptions(), HotSpotNodePlugin.Options.HotSpotPostOnExceptions, true);
|
||||
test(options, "snippet", (Object) null);
|
||||
}
|
||||
}
|
@ -618,8 +618,9 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase {
|
||||
public final long inlineCacheMissStub = getFieldValue("CompilerToVM::Data::SharedRuntime_ic_miss_stub", Long.class, "address");
|
||||
public final long handleWrongMethodStub = getFieldValue("CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", Long.class, "address");
|
||||
|
||||
public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address");
|
||||
public final long uncommonTrapStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", Long.class, "address");
|
||||
public final long deoptBlobUnpack = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address");
|
||||
public final long deoptBlobUnpackWithExceptionInTLS = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack_with_exception_in_tls", Long.class, "address", 0L);
|
||||
public final long deoptBlobUncommonTrap = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", Long.class, "address");
|
||||
|
||||
public final long codeCacheLowBound = versioned.codeCacheLowBound;
|
||||
public final long codeCacheHighBound = versioned.codeCacheHighBound;
|
||||
|
@ -31,13 +31,19 @@ import java.util.List;
|
||||
|
||||
import org.graalvm.compiler.api.replacements.MethodSubstitution;
|
||||
import org.graalvm.compiler.api.replacements.Snippet;
|
||||
import org.graalvm.compiler.bytecode.Bytecodes;
|
||||
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
|
||||
import org.graalvm.compiler.core.gen.DebugInfoBuilder;
|
||||
import org.graalvm.compiler.graph.GraalGraphError;
|
||||
import org.graalvm.compiler.graph.NodeSourcePosition;
|
||||
import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
|
||||
import org.graalvm.compiler.lir.VirtualStackSlot;
|
||||
import org.graalvm.compiler.nodes.FrameState;
|
||||
import org.graalvm.compiler.nodes.FullInfopointNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
|
||||
import org.graalvm.compiler.nodes.spi.NodeValueMap;
|
||||
import org.graalvm.compiler.nodes.spi.NodeWithState;
|
||||
|
||||
import jdk.vm.ci.code.BytecodeFrame;
|
||||
import jdk.vm.ci.code.StackLockValue;
|
||||
@ -87,11 +93,42 @@ public class HotSpotDebugInfoBuilder extends DebugInfoBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BytecodeFrame computeFrameForState(FrameState state) {
|
||||
protected boolean verifyFrameState(NodeWithState node, FrameState topState) {
|
||||
if (node instanceof FullInfopointNode) {
|
||||
return true;
|
||||
}
|
||||
if (node instanceof ForeignCallNode) {
|
||||
ForeignCallNode call = (ForeignCallNode) node;
|
||||
ForeignCallDescriptor descriptor = call.getDescriptor();
|
||||
if (DefaultHotSpotLoweringProvider.RuntimeCalls.runtimeCalls.containsValue(descriptor)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// There are many properties of FrameStates which could be validated though it's complicated
|
||||
// by some of the idiomatic ways that they are used. This check specifically tries to catch
|
||||
// cases where a FrameState that's constructed for reexecution has an incorrect stack depth
|
||||
// at invokes.
|
||||
if (topState.bci >= 0 && !topState.duringCall() && !topState.rethrowException()) {
|
||||
ResolvedJavaMethod m = topState.getMethod();
|
||||
int opcode = m.getCode()[topState.bci] & 0xff;
|
||||
if (opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKEINTERFACE) {
|
||||
assert topState.stackSize() > 0 : "expected non-empty stack: " + topState;
|
||||
} else {
|
||||
int stackEffect = Bytecodes.stackEffectOf(opcode);
|
||||
if (stackEffect < 0) {
|
||||
assert topState.stackSize() >= -stackEffect : "expected at least " + (-stackEffect) + " stack depth : " + topState;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BytecodeFrame computeFrameForState(NodeWithState node, FrameState state) {
|
||||
if (isPlaceholderBci(state.bci) && state.bci != BytecodeFrame.BEFORE_BCI) {
|
||||
raiseInvalidFrameStateError(state);
|
||||
}
|
||||
BytecodeFrame result = super.computeFrameForState(state);
|
||||
BytecodeFrame result = super.computeFrameForState(node, state);
|
||||
maxInterpreterFrameSize = Math.max(maxInterpreterFrameSize, codeCacheProvider.interpreterFrameSize(result));
|
||||
return result;
|
||||
}
|
||||
|
@ -67,12 +67,17 @@ public abstract class HotSpotHostBackend extends HotSpotBackend implements LIRGe
|
||||
/**
|
||||
* Descriptor for {@code SharedRuntime::deopt_blob()->unpack()}.
|
||||
*/
|
||||
public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
|
||||
public static final ForeignCallDescriptor DEOPT_BLOB_UNPACK = new ForeignCallDescriptor("deopt_blob()->unpack()", void.class);
|
||||
|
||||
/**
|
||||
* Descriptor for {@code SharedRuntime::deopt_blob()->unpack_with_exception_in_tls()}.
|
||||
*/
|
||||
public static final ForeignCallDescriptor DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS = new ForeignCallDescriptor("deopt_blob()->unpack_with_exception_in_tls()", void.class);
|
||||
|
||||
/**
|
||||
* Descriptor for {@code SharedRuntime::deopt_blob()->uncommon_trap()}.
|
||||
*/
|
||||
public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
|
||||
public static final ForeignCallDescriptor DEOPT_BLOB_UNCOMMON_TRAP = new ForeignCallDescriptor("deopt_blob()->uncommon_trap()", void.class);
|
||||
|
||||
public static final ForeignCallDescriptor ENABLE_STACK_RESERVED_ZONE = new ForeignCallDescriptor("enableStackReservedZoneEntry", void.class, Word.class);
|
||||
|
||||
|
@ -61,8 +61,20 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool {
|
||||
*/
|
||||
void emitTailcall(Value[] args, Value address);
|
||||
|
||||
/**
|
||||
* Emits code that jumps to the deopt blob uncommon_trap entry point with {@code action} and
|
||||
* {@code reason}.
|
||||
*/
|
||||
void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
|
||||
|
||||
/**
|
||||
* Emits code that jumps to the deopt blob unpack_with_exception entry point with
|
||||
* {@code exception}.
|
||||
*
|
||||
* @param exception
|
||||
*/
|
||||
void emitDeoptimizeWithExceptionInCaller(Value exception);
|
||||
|
||||
/**
|
||||
* Emits code for a {@link LoadConstantIndirectlyNode}.
|
||||
*
|
||||
|
@ -722,7 +722,13 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
|
||||
|
||||
StructuredGraph graph = node.graph();
|
||||
ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(NodeView.DEFAULT), node.getArguments()));
|
||||
foreignCallNode.setStateAfter(node.stateAfter());
|
||||
/*
|
||||
* The original BytecodeExceptionNode has a rethrowException FrameState which isn't suitable
|
||||
* for deopt because the exception to be thrown come from this call so it's not available in
|
||||
* the debug info. The foreign call needs a stateDuring instead so it can deopt with a
|
||||
* pending exception.
|
||||
*/
|
||||
foreignCallNode.setStateAfter(node.createStateDuring());
|
||||
graph.replaceFixedWithFixed(node, foreignCallNode);
|
||||
}
|
||||
|
||||
|
@ -74,10 +74,11 @@ import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.
|
||||
import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NO_VZERO;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.STACK_INSPECTABLE_LEAF;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNPACK;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.ENABLE_STACK_RESERVED_ZONE;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.THROW_DELAYED_STACKOVERFLOW_ERROR;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.replacements.AssertionSnippets.ASSERTION_VM_MESSAGE_C;
|
||||
import static org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets.G1WBPOSTCALL;
|
||||
import static org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets.G1WBPRECALL;
|
||||
@ -270,8 +271,11 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall
|
||||
|
||||
public void initialize(HotSpotProviders providers, OptionValues options) {
|
||||
GraalHotSpotVMConfig c = runtime.getVMConfig();
|
||||
registerForeignCall(DEOPTIMIZATION_HANDLER, c.handleDeoptStub, NativeCall, LEAF_NO_VZERO, REEXECUTABLE, NO_LOCATIONS);
|
||||
registerForeignCall(UNCOMMON_TRAP_HANDLER, c.uncommonTrapStub, NativeCall, LEAF_NO_VZERO, REEXECUTABLE, NO_LOCATIONS);
|
||||
registerForeignCall(DEOPT_BLOB_UNPACK, c.deoptBlobUnpack, NativeCall, LEAF_NO_VZERO, REEXECUTABLE, NO_LOCATIONS);
|
||||
if (c.deoptBlobUnpackWithExceptionInTLS != 0) {
|
||||
registerForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS, c.deoptBlobUnpackWithExceptionInTLS, NativeCall, LEAF_NO_VZERO, REEXECUTABLE, NO_LOCATIONS);
|
||||
}
|
||||
registerForeignCall(DEOPT_BLOB_UNCOMMON_TRAP, c.deoptBlobUncommonTrap, NativeCall, LEAF_NO_VZERO, REEXECUTABLE, NO_LOCATIONS);
|
||||
registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall, LEAF_NO_VZERO, REEXECUTABLE, NO_LOCATIONS);
|
||||
|
||||
if (c.enableStackReservedZoneAddress != 0) {
|
||||
|
@ -27,6 +27,9 @@ package org.graalvm.compiler.hotspot.meta;
|
||||
import static jdk.vm.ci.meta.DeoptimizationAction.None;
|
||||
import static jdk.vm.ci.meta.DeoptimizationReason.TransferToInterpreter;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotNodePlugin.Options.HotSpotPostOnExceptions;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
@ -38,6 +41,7 @@ import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
import org.graalvm.compiler.nodes.FixedGuardNode;
|
||||
import org.graalvm.compiler.nodes.FixedWithNextNode;
|
||||
import org.graalvm.compiler.nodes.FrameState;
|
||||
import org.graalvm.compiler.nodes.LogicNode;
|
||||
import org.graalvm.compiler.nodes.NamedLocationIdentity;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
@ -54,6 +58,9 @@ import org.graalvm.compiler.nodes.memory.ReadNode;
|
||||
import org.graalvm.compiler.nodes.memory.address.AddressNode;
|
||||
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
|
||||
import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
|
||||
import org.graalvm.compiler.word.Word;
|
||||
import org.graalvm.compiler.word.WordOperationPlugin;
|
||||
@ -82,6 +89,11 @@ import sun.misc.Unsafe;
|
||||
* </ul>
|
||||
*/
|
||||
public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
|
||||
public static class Options {
|
||||
@Option(help = "Testing only option that forces deopts for exception throws", type = OptionType.Expert)//
|
||||
public static final OptionKey<Boolean> HotSpotPostOnExceptions = new OptionKey<>(false);
|
||||
}
|
||||
|
||||
private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
|
||||
protected final WordOperationPlugin wordOperationPlugin;
|
||||
private final GraalHotSpotVMConfig config;
|
||||
@ -209,35 +221,39 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded) {
|
||||
public FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded, Supplier<FrameState> frameStateFunction) {
|
||||
CompilationIdentifier id = graph.compilationId();
|
||||
if (id instanceof HotSpotCompilationIdentifier) {
|
||||
if (id instanceof HotSpotCompilationIdentifier &&
|
||||
config.jvmciCompileStateCanPostOnExceptionsOffset != Integer.MIN_VALUE &&
|
||||
config.javaThreadShouldPostOnExceptionsFlagOffset != Integer.MIN_VALUE) {
|
||||
boolean canPostOnExceptions = HotSpotPostOnExceptions.getValue(graph.getOptions());
|
||||
HotSpotCompilationRequest request = ((HotSpotCompilationIdentifier) id).getRequest();
|
||||
if (request != null) {
|
||||
long compileState = request.getJvmciEnv();
|
||||
if (compileState != 0 &&
|
||||
config.jvmciCompileStateCanPostOnExceptionsOffset != Integer.MIN_VALUE &&
|
||||
config.javaThreadShouldPostOnExceptionsFlagOffset != Integer.MIN_VALUE) {
|
||||
if (compileState != 0) {
|
||||
long canPostOnExceptionsOffset = compileState + config.jvmciCompileStateCanPostOnExceptionsOffset;
|
||||
boolean canPostOnExceptions = UNSAFE.getByte(canPostOnExceptionsOffset) != 0;
|
||||
if (canPostOnExceptions) {
|
||||
// If the exception capability is set, then generate code
|
||||
// to check the JavaThread.should_post_on_exceptions flag to see
|
||||
// if we actually need to report exception events for the current
|
||||
// thread. If not, take the fast path otherwise deoptimize.
|
||||
CurrentJavaThreadNode thread = graph.unique(new CurrentJavaThreadNode(wordTypes.getWordKind()));
|
||||
ValueNode offset = graph.unique(ConstantNode.forLong(config.javaThreadShouldPostOnExceptionsFlagOffset));
|
||||
AddressNode address = graph.unique(new OffsetAddressNode(thread, offset));
|
||||
ReadNode shouldPostException = graph.add(new ReadNode(address, JAVA_THREAD_SHOULD_POST_ON_EXCEPTIONS_FLAG_LOCATION, StampFactory.intValue(), BarrierType.NONE));
|
||||
afterExceptionLoaded.setNext(shouldPostException);
|
||||
ValueNode zero = graph.unique(ConstantNode.forInt(0));
|
||||
LogicNode cond = graph.unique(new IntegerEqualsNode(shouldPostException, zero));
|
||||
FixedGuardNode check = graph.add(new FixedGuardNode(cond, TransferToInterpreter, None, false));
|
||||
shouldPostException.setNext(check);
|
||||
return check;
|
||||
}
|
||||
canPostOnExceptions = UNSAFE.getByte(canPostOnExceptionsOffset) != 0;
|
||||
}
|
||||
}
|
||||
if (canPostOnExceptions) {
|
||||
// If the exception capability is set, then generate code
|
||||
// to check the JavaThread.should_post_on_exceptions flag to see
|
||||
// if we actually need to report exception events for the current
|
||||
// thread. If not, take the fast path otherwise deoptimize.
|
||||
CurrentJavaThreadNode thread = graph.unique(new CurrentJavaThreadNode(wordTypes.getWordKind()));
|
||||
ValueNode offset = graph.unique(ConstantNode.forLong(config.javaThreadShouldPostOnExceptionsFlagOffset));
|
||||
AddressNode address = graph.unique(new OffsetAddressNode(thread, offset));
|
||||
ReadNode shouldPostException = graph.add(new ReadNode(address, JAVA_THREAD_SHOULD_POST_ON_EXCEPTIONS_FLAG_LOCATION, StampFactory.intValue(), BarrierType.NONE));
|
||||
afterExceptionLoaded.setNext(shouldPostException);
|
||||
ValueNode zero = graph.unique(ConstantNode.forInt(0));
|
||||
LogicNode cond = graph.unique(new IntegerEqualsNode(shouldPostException, zero));
|
||||
FixedGuardNode check = graph.add(new FixedGuardNode(cond, TransferToInterpreter, None, false));
|
||||
FrameState fs = frameStateFunction.get();
|
||||
assert fs.stackSize() == 1 && fs.rethrowException() : "expected rethrow exception FrameState";
|
||||
check.setStateBefore(fs);
|
||||
shouldPostException.setNext(check);
|
||||
return check;
|
||||
}
|
||||
}
|
||||
return afterExceptionLoaded;
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.nodes;
|
||||
|
||||
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
|
||||
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.nodes.ControlSinkNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.spi.LIRLowerable;
|
||||
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
||||
|
||||
import jdk.vm.ci.meta.Value;
|
||||
|
||||
/**
|
||||
* Removes the current frame and tail calls the uncommon trap routine.
|
||||
*/
|
||||
@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
|
||||
public final class DeoptimizeWithExceptionInCallerNode extends ControlSinkNode implements LIRLowerable {
|
||||
public static final NodeClass<DeoptimizeWithExceptionInCallerNode> TYPE = NodeClass.create(DeoptimizeWithExceptionInCallerNode.class);
|
||||
|
||||
@Input protected ValueNode exception;
|
||||
|
||||
public DeoptimizeWithExceptionInCallerNode(ValueNode exception) {
|
||||
super(TYPE, StampFactory.forVoid());
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(NodeLIRBuilderTool gen) {
|
||||
Value e = gen.operand(exception);
|
||||
((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizeWithExceptionInCaller(e);
|
||||
}
|
||||
|
||||
@NodeIntrinsic
|
||||
public static native void deopt(Object exception);
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.replacements;
|
||||
|
||||
import static org.graalvm.compiler.nodeinfo.InputType.Memory;
|
||||
import static org.graalvm.compiler.nodeinfo.InputType.State;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
|
||||
@ -40,7 +41,7 @@ import org.graalvm.compiler.nodes.spi.Lowerable;
|
||||
import org.graalvm.compiler.nodes.spi.LoweringTool;
|
||||
import jdk.internal.vm.compiler.word.LocationIdentity;
|
||||
|
||||
@NodeInfo(cycles = CYCLES_2, size = SIZE_0)
|
||||
@NodeInfo(cycles = CYCLES_2, size = SIZE_0, allowedUsageTypes = Memory)
|
||||
public class FastNotifyNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, DeoptimizingNode.DeoptDuring {
|
||||
|
||||
public static final NodeClass<FastNotifyNode> TYPE = NodeClass.create(FastNotifyNode.class);
|
||||
|
@ -25,6 +25,7 @@
|
||||
package org.graalvm.compiler.hotspot.stubs;
|
||||
|
||||
import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
|
||||
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_OPTIONVALUES;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Reexecutability.REEXECUTABLE;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
|
||||
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException;
|
||||
@ -36,11 +37,16 @@ import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
|
||||
import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
|
||||
import org.graalvm.compiler.graph.Node.NodeIntrinsic;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase;
|
||||
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
|
||||
import org.graalvm.compiler.hotspot.nodes.DeoptimizeWithExceptionInCallerNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
|
||||
import org.graalvm.compiler.hotspot.word.KlassPointer;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.replacements.nodes.CStringConstant;
|
||||
import org.graalvm.compiler.word.Word;
|
||||
@ -53,10 +59,25 @@ import jdk.vm.ci.code.Register;
|
||||
*/
|
||||
public class CreateExceptionStub extends SnippetStub {
|
||||
|
||||
public static class Options {
|
||||
@Option(help = "Testing only option that forces deopts for exception throws", type = OptionType.Expert)//
|
||||
public static final OptionKey<Boolean> HotSpotDeoptExplicitExceptions = new OptionKey<>(false);
|
||||
}
|
||||
|
||||
protected CreateExceptionStub(String snippetMethodName, OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
|
||||
super(snippetMethodName, options, providers, linkage);
|
||||
}
|
||||
|
||||
@Fold
|
||||
static boolean reportsDeoptimization(@Fold.InjectedParameter GraalHotSpotVMConfig config) {
|
||||
return config.deoptBlobUnpackWithExceptionInTLS != 0;
|
||||
}
|
||||
|
||||
@Fold
|
||||
static boolean alwayDeoptimize(@Fold.InjectedParameter OptionValues options) {
|
||||
return Options.HotSpotDeoptExplicitExceptions.getValue(options);
|
||||
}
|
||||
|
||||
@Fold
|
||||
static String getInternalClassName(Class<?> cls) {
|
||||
return cls.getName().replace('.', '/');
|
||||
@ -73,36 +94,44 @@ public class CreateExceptionStub extends SnippetStub {
|
||||
|
||||
protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, Word message) {
|
||||
Word thread = registerAsWord(threadRegister);
|
||||
throwAndPostJvmtiException(THROW_AND_POST_JVMTI_EXCEPTION, thread, classAsCString(exception), message);
|
||||
return clearPendingException(thread);
|
||||
int deoptimized = throwAndPostJvmtiException(THROW_AND_POST_JVMTI_EXCEPTION, thread, classAsCString(exception), message);
|
||||
return handleExceptionReturn(thread, deoptimized);
|
||||
}
|
||||
|
||||
protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, KlassPointer klass) {
|
||||
Word thread = registerAsWord(threadRegister);
|
||||
throwKlassExternalNameException(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, thread, classAsCString(exception), klass);
|
||||
return clearPendingException(thread);
|
||||
int deoptimized = throwKlassExternalNameException(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, thread, classAsCString(exception), klass);
|
||||
return handleExceptionReturn(thread, deoptimized);
|
||||
}
|
||||
|
||||
protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, KlassPointer objKlass, KlassPointer targetKlass) {
|
||||
Word thread = registerAsWord(threadRegister);
|
||||
throwClassCastException(THROW_CLASS_CAST_EXCEPTION, thread, classAsCString(exception), objKlass, targetKlass);
|
||||
return clearPendingException(thread);
|
||||
int deoptimized = throwClassCastException(THROW_CLASS_CAST_EXCEPTION, thread, classAsCString(exception), objKlass, targetKlass);
|
||||
return handleExceptionReturn(thread, deoptimized);
|
||||
}
|
||||
|
||||
private static final ForeignCallDescriptor THROW_AND_POST_JVMTI_EXCEPTION = new ForeignCallDescriptor("throw_and_post_jvmti_exception", void.class, Word.class, Word.class, Word.class);
|
||||
private static final ForeignCallDescriptor THROW_KLASS_EXTERNAL_NAME_EXCEPTION = new ForeignCallDescriptor("throw_klass_external_name_exception", void.class, Word.class, Word.class,
|
||||
private static Object handleExceptionReturn(Word thread, int deoptimized) {
|
||||
Object clearPendingException = clearPendingException(thread);
|
||||
if (alwayDeoptimize(INJECTED_OPTIONVALUES) || (reportsDeoptimization(GraalHotSpotVMConfigBase.INJECTED_VMCONFIG) && deoptimized != 0)) {
|
||||
DeoptimizeWithExceptionInCallerNode.deopt(clearPendingException);
|
||||
}
|
||||
return clearPendingException;
|
||||
}
|
||||
|
||||
private static final ForeignCallDescriptor THROW_AND_POST_JVMTI_EXCEPTION = new ForeignCallDescriptor("throw_and_post_jvmti_exception", int.class, Word.class, Word.class, Word.class);
|
||||
private static final ForeignCallDescriptor THROW_KLASS_EXTERNAL_NAME_EXCEPTION = new ForeignCallDescriptor("throw_klass_external_name_exception", int.class, Word.class, Word.class,
|
||||
KlassPointer.class);
|
||||
private static final ForeignCallDescriptor THROW_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("throw_class_cast_exception", void.class, Word.class, Word.class, KlassPointer.class,
|
||||
private static final ForeignCallDescriptor THROW_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("throw_class_cast_exception", int.class, Word.class, Word.class, KlassPointer.class,
|
||||
KlassPointer.class);
|
||||
|
||||
@NodeIntrinsic(StubForeignCallNode.class)
|
||||
private static native void throwAndPostJvmtiException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, Word message);
|
||||
private static native int throwAndPostJvmtiException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, Word message);
|
||||
|
||||
@NodeIntrinsic(StubForeignCallNode.class)
|
||||
private static native void throwKlassExternalNameException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer klass);
|
||||
private static native int throwKlassExternalNameException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer klass);
|
||||
|
||||
@NodeIntrinsic(StubForeignCallNode.class)
|
||||
private static native void throwClassCastException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer objKlass, KlassPointer targetKlass);
|
||||
private static native int throwClassCastException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer objKlass, KlassPointer targetKlass);
|
||||
|
||||
public static void registerForeignCalls(GraalHotSpotVMConfig c, HotSpotForeignCallsProviderImpl foreignCalls) {
|
||||
foreignCalls.registerForeignCall(THROW_AND_POST_JVMTI_EXCEPTION, c.throwAndPostJvmtiExceptionAddress, NativeCall, SAFEPOINT, REEXECUTABLE, any());
|
||||
|
@ -30,7 +30,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
|
||||
import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM;
|
||||
import static org.graalvm.compiler.debug.DebugOptions.DebugStubsAndSnippets;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP;
|
||||
import static org.graalvm.util.CollectionsUtil.allMatch;
|
||||
|
||||
import java.util.ListIterator;
|
||||
@ -288,7 +288,7 @@ public abstract class Stub {
|
||||
Call call = (Call) infopoint;
|
||||
assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target;
|
||||
HotSpotForeignCallLinkage callLinkage = (HotSpotForeignCallLinkage) call.target;
|
||||
assert !callLinkage.isCompiledStub() || callLinkage.getDescriptor().equals(UNCOMMON_TRAP_HANDLER) : this + " cannot call compiled stub " + callLinkage;
|
||||
assert !callLinkage.isCompiledStub() || callLinkage.getDescriptor().equals(DEOPT_BLOB_UNCOMMON_TRAP) : this + " cannot call compiled stub " + callLinkage;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1321,10 +1321,10 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
AbstractBeginNode dispatchBegin;
|
||||
if (exceptionObject == null) {
|
||||
ExceptionObjectNode newExceptionObject = graph.add(new ExceptionObjectNode(getMetaAccess()));
|
||||
dispatchBegin = newExceptionObject;
|
||||
dispatchState.push(JavaKind.Object, dispatchBegin);
|
||||
dispatchState.push(JavaKind.Object, newExceptionObject);
|
||||
dispatchState.setRethrowException(true);
|
||||
newExceptionObject.setStateAfter(dispatchState.create(bci, newExceptionObject));
|
||||
dispatchBegin = newExceptionObject;
|
||||
} else {
|
||||
dispatchBegin = graph.add(new BeginNode());
|
||||
dispatchState.push(JavaKind.Object, exceptionObject);
|
||||
@ -1346,7 +1346,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
protected void createHandleExceptionTarget(FixedWithNextNode afterExceptionLoaded, int bci, FrameStateBuilder dispatchState) {
|
||||
FixedWithNextNode afterInstrumentation = afterExceptionLoaded;
|
||||
for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
|
||||
afterInstrumentation = plugin.instrumentExceptionDispatch(graph, afterInstrumentation);
|
||||
afterInstrumentation = plugin.instrumentExceptionDispatch(graph, afterInstrumentation, () -> dispatchState.create(bci, getNonIntrinsicAncestor(), false, null, null));
|
||||
assert afterInstrumentation.next() == null : "exception dispatch instrumentation will be linked to dispatch block";
|
||||
}
|
||||
|
||||
@ -1611,7 +1611,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
append(new IfNode(condition, trueSuccessor, falseSuccessor, passingOnTrue ? LUDICROUSLY_FAST_PATH_PROBABILITY : LUDICROUSLY_SLOW_PATH_PROBABILITY));
|
||||
lastInstr = passingSuccessor;
|
||||
|
||||
exception.setStateAfter(createFrameState(bci(), exception));
|
||||
exception.setStateAfter(createBytecodeExceptionFrameState(bci(), exception));
|
||||
exception.setNext(handleException(exception, bci(), false));
|
||||
EXPLICIT_EXCEPTIONS.increment(debug);
|
||||
|
||||
@ -3909,12 +3909,24 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
|
||||
private FrameState createFrameState(int bci, StateSplit forStateSplit) {
|
||||
assert !(forStateSplit instanceof BytecodeExceptionNode);
|
||||
if (currentBlock != null && bci > currentBlock.endBci) {
|
||||
frameState.clearNonLiveLocals(currentBlock, liveness, false);
|
||||
}
|
||||
return frameState.create(bci, forStateSplit);
|
||||
}
|
||||
|
||||
private FrameState createBytecodeExceptionFrameState(int bci, BytecodeExceptionNode bytecodeException) {
|
||||
FrameStateBuilder copy = frameState.copy();
|
||||
copy.clearStack();
|
||||
if (currentBlock != null) {
|
||||
copy.clearNonLiveLocals(currentBlock, liveness, false);
|
||||
}
|
||||
copy.setRethrowException(true);
|
||||
copy.push(JavaKind.Object, bytecodeException);
|
||||
return copy.create(bci, bytecodeException);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStateAfter(StateSplit sideEffect) {
|
||||
assert sideEffect.hasSideEffect() || sideEffect instanceof AbstractMergeNode;
|
||||
@ -4747,7 +4759,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
@Override
|
||||
public AbstractBeginNode genExplicitExceptionEdge(BytecodeExceptionKind exceptionKind) {
|
||||
BytecodeExceptionNode exceptionNode = graph.add(new BytecodeExceptionNode(getMetaAccess(), exceptionKind));
|
||||
exceptionNode.setStateAfter(createFrameState(bci(), exceptionNode));
|
||||
exceptionNode.setStateAfter(createBytecodeExceptionFrameState(bci(), exceptionNode));
|
||||
AbstractBeginNode exceptionDispatch = handleException(exceptionNode, bci(), false);
|
||||
exceptionNode.setNext(exceptionDispatch);
|
||||
return BeginNode.begin(exceptionNode);
|
||||
|
@ -351,6 +351,10 @@ public final class FrameState extends VirtualState implements IterableNodeType {
|
||||
return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, new JavaKind[]{pushedSlotKind}, new ValueNode[]{pushedValue});
|
||||
}
|
||||
|
||||
public FrameState duplicateRethrow(ValueNode exceptionObject) {
|
||||
return duplicateModified(graph(), bci, true, duringCall, JavaKind.Void, new JavaKind[]{JavaKind.Object}, new ValueNode[]{exceptionObject});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this frame state with one stack element of type popKind popped from the
|
||||
* stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
|
||||
|
@ -38,6 +38,7 @@ import org.graalvm.compiler.graph.spi.Canonicalizable;
|
||||
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.nodeinfo.Verbosity;
|
||||
import org.graalvm.compiler.nodes.FrameState;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
|
||||
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
|
||||
@ -45,6 +46,7 @@ import org.graalvm.compiler.nodes.spi.Lowerable;
|
||||
import org.graalvm.compiler.nodes.spi.LoweringTool;
|
||||
import jdk.internal.vm.compiler.word.LocationIdentity;
|
||||
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
|
||||
/**
|
||||
@ -106,7 +108,7 @@ public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implem
|
||||
|
||||
@Override
|
||||
public Node canonical(CanonicalizerTool tool) {
|
||||
if (tool.allUsagesAvailable() && getUsageCount() == 0) {
|
||||
if (tool.allUsagesAvailable() && (hasNoUsages() || (hasExactlyOneUsage() && usages().first() == stateAfter))) {
|
||||
return null;
|
||||
}
|
||||
return this;
|
||||
@ -120,4 +122,13 @@ public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implem
|
||||
public NodeInputList<ValueNode> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new stateDuring for use by a foreign call.
|
||||
*/
|
||||
public FrameState createStateDuring() {
|
||||
return stateAfter.duplicateModified(graph(), stateAfter.bci, /* rethrowException */ false, /* duringCall */ true,
|
||||
JavaKind.Object, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowe
|
||||
(currentStateAfter.stackSize() > 1 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 2) == this)) {
|
||||
// The result of this call is on the top of stack, so roll back to the previous bci.
|
||||
assert bci != BytecodeFrame.UNKNOWN_BCI : this;
|
||||
newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, this.getStackKind());
|
||||
newStateDuring = currentStateAfter.duplicateModified(currentStateAfter.graph(), bci, false, true, this.getStackKind(), null, null);
|
||||
} else {
|
||||
newStateDuring = currentStateAfter;
|
||||
}
|
||||
|
@ -24,8 +24,11 @@
|
||||
|
||||
package org.graalvm.compiler.nodes.graphbuilderconf;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.graalvm.compiler.graph.Node.ValueNumberable;
|
||||
import org.graalvm.compiler.nodes.FixedWithNextNode;
|
||||
import org.graalvm.compiler.nodes.FrameState;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.extended.GuardingNode;
|
||||
@ -226,9 +229,10 @@ public interface NodePlugin extends GraphBuilderPlugin {
|
||||
*
|
||||
* @param graph the graph being parsed
|
||||
* @param afterExceptionLoaded the last fixed node after loading the exception
|
||||
* @param frameStateFunction a helper that produces a FrameState suitable for deopt
|
||||
* @return the last fixed node after instrumentation
|
||||
*/
|
||||
default FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded) {
|
||||
default FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded, Supplier<FrameState> frameStateFunction) {
|
||||
return afterExceptionLoaded;
|
||||
}
|
||||
|
||||
|
@ -33,39 +33,11 @@ import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class ArrayStoreBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
|
||||
private static class Exceptions {
|
||||
|
||||
private static Object[] array = new Exceptions[1];
|
||||
|
||||
public static void throwArrayStore(Object obj) {
|
||||
array[0] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
|
||||
invocationPlugins.register(new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj) {
|
||||
return throwBytecodeException(b, BytecodeExceptionKind.ARRAY_STORE, obj);
|
||||
}
|
||||
}, Exceptions.class, "throwArrayStore", Object.class);
|
||||
super.registerInvocationPlugins(invocationPlugins);
|
||||
}
|
||||
|
||||
public static void arrayStoreSnippet(Object obj) {
|
||||
Exceptions.throwArrayStore(obj);
|
||||
public static void arrayStoreSnippet(Object[] array, Object obj) {
|
||||
array[0] = obj;
|
||||
}
|
||||
|
||||
@Parameter(0) public Object object;
|
||||
@ -84,6 +56,6 @@ public class ArrayStoreBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
|
||||
@Test
|
||||
public void testArrayStoreException() {
|
||||
test("arrayStoreSnippet", object);
|
||||
test("arrayStoreSnippet", new ArrayStoreBytecodeExceptionTest[1], object);
|
||||
}
|
||||
}
|
||||
|
@ -24,18 +24,27 @@
|
||||
|
||||
package org.graalvm.compiler.replacements.test;
|
||||
|
||||
import static org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode.CheckAll;
|
||||
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.nodes.UnwindNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
|
||||
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public abstract class BytecodeExceptionTest extends GraalCompilerTest {
|
||||
|
||||
protected boolean throwBytecodeException(GraphBuilderContext b, BytecodeExceptionKind exception, ValueNode... arguments) {
|
||||
BytecodeExceptionNode exceptionNode = b.add(new BytecodeExceptionNode(b.getMetaAccess(), exception, arguments));
|
||||
b.add(new UnwindNode(exceptionNode));
|
||||
return true;
|
||||
@Override
|
||||
protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
|
||||
return super.editGraphBuilderConfiguration(conf).withBytecodeExceptionMode(CheckAll);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result test(OptionValues options, ResolvedJavaMethod method, Object receiver, Object... args) {
|
||||
StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.NO);
|
||||
assertTrue("no BytecodeExceptionNode generated", graph.getNodes().filter(BytecodeExceptionNode.class).isNotEmpty());
|
||||
return super.test(options, method, receiver, args);
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package org.graalvm.compiler.replacements.test;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -34,64 +35,9 @@ import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.common.type.Stamp;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.core.common.type.TypeReference;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
|
||||
|
||||
import jdk.vm.ci.meta.Constant;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class ClassCastBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
|
||||
private static class Exceptions {
|
||||
|
||||
public static void throwClassCast(Object obj, Class<?> cls) {
|
||||
/*
|
||||
* We don't use cls.cast(obj) here because that gives a different exception message than
|
||||
* the checkcast bytecode.
|
||||
*/
|
||||
if (cls == Double.class) {
|
||||
Double cast = (Double) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if (cls == byte[].class) {
|
||||
byte[] cast = (byte[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if (cls == String[].class) {
|
||||
String[] cast = (String[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if (cls == Object[][].class) {
|
||||
Object[][] cast = (Object[][]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else {
|
||||
Assert.fail("unexpected class argument");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
|
||||
invocationPlugins.register(new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj, ValueNode classNode) {
|
||||
ResolvedJavaType type = b.getConstantReflection().asJavaType(classNode.asConstant());
|
||||
Constant hub = b.getConstantReflection().asObjectHub(type);
|
||||
Stamp hubStamp = b.getStampProvider().createHubStamp(StampFactory.object(TypeReference.createExactTrusted(type)));
|
||||
ConstantNode hubConst = b.add(ConstantNode.forConstant(hubStamp, hub, b.getMetaAccess()));
|
||||
return throwBytecodeException(b, BytecodeExceptionKind.CLASS_CAST, obj, hubConst);
|
||||
}
|
||||
}, Exceptions.class, "throwClassCast", Object.class, Class.class);
|
||||
super.registerInvocationPlugins(invocationPlugins);
|
||||
}
|
||||
|
||||
@Parameter(0) public Object object;
|
||||
@Parameter(1) public Class<?> cls;
|
||||
|
||||
@ -107,7 +53,25 @@ public class ClassCastBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
}
|
||||
|
||||
public static void castToDouble(Object obj) {
|
||||
Exceptions.throwClassCast(obj, Double.class);
|
||||
/*
|
||||
* We don't use cls.cast(obj) here because that gives a different exception message than the
|
||||
* checkcast bytecode.
|
||||
*/
|
||||
if (Double.class == Double.class) {
|
||||
Double cast = (Double) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) Double.class == byte[].class) {
|
||||
byte[] cast = (byte[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) Double.class == String[].class) {
|
||||
String[] cast = (String[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) Double.class == Object[][].class) {
|
||||
Object[][] cast = (Object[][]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else {
|
||||
Assert.fail("unexpected class argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -116,7 +80,25 @@ public class ClassCastBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
}
|
||||
|
||||
public static void castToByteArray(Object obj) {
|
||||
Exceptions.throwClassCast(obj, byte[].class);
|
||||
/*
|
||||
* We don't use cls.cast(obj) here because that gives a different exception message than the
|
||||
* checkcast bytecode.
|
||||
*/
|
||||
if ((Class<?>) byte[].class == Double.class) {
|
||||
Double cast = (Double) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if (byte[].class == byte[].class) {
|
||||
byte[] cast = (byte[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) byte[].class == String[].class) {
|
||||
String[] cast = (String[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) byte[].class == Object[][].class) {
|
||||
Object[][] cast = (Object[][]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else {
|
||||
Assert.fail("unexpected class argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -125,7 +107,25 @@ public class ClassCastBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
}
|
||||
|
||||
public static void castToStringArray(Object obj) {
|
||||
Exceptions.throwClassCast(obj, String[].class);
|
||||
/*
|
||||
* We don't use cls.cast(obj) here because that gives a different exception message than the
|
||||
* checkcast bytecode.
|
||||
*/
|
||||
if ((Class<?>) String[].class == Double.class) {
|
||||
Double cast = (Double) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) String[].class == byte[].class) {
|
||||
byte[] cast = (byte[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if (String[].class == String[].class) {
|
||||
String[] cast = (String[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) String[].class == Object[][].class) {
|
||||
Object[][] cast = (Object[][]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else {
|
||||
Assert.fail("unexpected class argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -134,7 +134,25 @@ public class ClassCastBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
}
|
||||
|
||||
public static void castToArrayArray(Object obj) {
|
||||
Exceptions.throwClassCast(obj, Object[][].class);
|
||||
/*
|
||||
* We don't use cls.cast(obj) here because that gives a different exception message than the
|
||||
* checkcast bytecode.
|
||||
*/
|
||||
if ((Class<?>) Object[][].class == Double.class) {
|
||||
Double cast = (Double) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) Object[][].class == byte[].class) {
|
||||
byte[] cast = (byte[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if ((Class<?>) Object[][].class == String[].class) {
|
||||
String[] cast = (String[]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else if (Object[][].class == Object[][].class) {
|
||||
Object[][] cast = (Object[][]) obj;
|
||||
GraalDirectives.blackhole(cast);
|
||||
} else {
|
||||
Assert.fail("unexpected class argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -27,47 +27,19 @@ package org.graalvm.compiler.replacements.test;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class IndexOobBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
|
||||
private static class Exceptions {
|
||||
|
||||
private static Object[] empty = new Object[0];
|
||||
|
||||
public static void throwOutOfBounds(int idx, int length) {
|
||||
GraalDirectives.blackhole(empty[idx]);
|
||||
GraalDirectives.blackhole(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
|
||||
invocationPlugins.register(new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode idx, ValueNode length) {
|
||||
return throwBytecodeException(b, BytecodeExceptionKind.OUT_OF_BOUNDS, idx, length);
|
||||
}
|
||||
}, Exceptions.class, "throwOutOfBounds", int.class, int.class);
|
||||
super.registerInvocationPlugins(invocationPlugins);
|
||||
}
|
||||
|
||||
public static void oobSnippet(int idx, int length) {
|
||||
Exceptions.throwOutOfBounds(idx, length);
|
||||
public static void oobSnippet(Object[] empty, int idx, int length) {
|
||||
GraalDirectives.blackhole(empty[idx]);
|
||||
GraalDirectives.blackhole(length);
|
||||
}
|
||||
|
||||
@Parameter public int index;
|
||||
@ -85,6 +57,7 @@ public class IndexOobBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
|
||||
@Test
|
||||
public void testOutOfBoundsException() {
|
||||
test("oobSnippet", index, Exceptions.empty.length);
|
||||
Object[] empty = new Object[0];
|
||||
test("oobSnippet", empty, index, empty.length);
|
||||
}
|
||||
}
|
||||
|
@ -25,41 +25,15 @@
|
||||
package org.graalvm.compiler.replacements.test;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class NullBytecodeExceptionTest extends BytecodeExceptionTest {
|
||||
|
||||
private static class Exceptions {
|
||||
|
||||
private static Object obj = null;
|
||||
|
||||
public static void throwNull() {
|
||||
obj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
|
||||
invocationPlugins.register(new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
|
||||
return throwBytecodeException(b, BytecodeExceptionKind.NULL_POINTER);
|
||||
}
|
||||
}, Exceptions.class, "throwNull");
|
||||
super.registerInvocationPlugins(invocationPlugins);
|
||||
}
|
||||
|
||||
public static void nullSnippet() {
|
||||
Exceptions.throwNull();
|
||||
public static void nullSnippet(Object obj) {
|
||||
obj.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullPointerException() {
|
||||
test("nullSnippet");
|
||||
test("nullSnippet", (Object) null);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2020, 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
|
||||
@ -115,7 +115,7 @@ public class Basic {
|
||||
/**
|
||||
* Test: Enumerate all FileStores
|
||||
*/
|
||||
if (FileUtils.areAllMountPointsAccessible()) {
|
||||
if (FileUtils.areMountPointsAccessibleAndUnique()) {
|
||||
FileStore prev = null;
|
||||
for (FileStore store: FileSystems.getDefault().getFileStores()) {
|
||||
System.out.format("%s (name=%s type=%s)\n", store, store.name(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2020, 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
|
||||
@ -47,6 +47,7 @@ import java.util.ArrayDeque;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -242,87 +243,84 @@ public final class FileUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether all file systems are accessible. This is performed
|
||||
* by checking free disk space on all mounted file systems via a
|
||||
* separate, spawned process. File systems are considered to be
|
||||
* accessible if this process completes successfully before a given
|
||||
* fixed duration has elapsed.
|
||||
* Checks whether all file systems are accessible and there are no
|
||||
* duplicate mount points. This is performed by checking free disk
|
||||
* space on all mounted file systems via a separate, spawned process.
|
||||
* File systems are considered to be accessible if this process completes
|
||||
* successfully before a given fixed duration has elapsed.
|
||||
*
|
||||
* @implNote On Unix this executes the {@code df} command in a separate
|
||||
* process and on Windows always returns {@code true}.
|
||||
*
|
||||
* @return whether file systems appear to be accessible
|
||||
*
|
||||
* @throws RuntimeException if there are duplicate mount points or some
|
||||
* other execution problem occurs
|
||||
* @return whether file systems appear to be accessible and duplicate-free
|
||||
*/
|
||||
public static boolean areAllMountPointsAccessible() {
|
||||
final AtomicBoolean areMountPointsOK = new AtomicBoolean(true);
|
||||
if (!IS_WINDOWS) {
|
||||
Thread thr = new Thread(() -> {
|
||||
try {
|
||||
Process proc = new ProcessBuilder("df").start();
|
||||
BufferedReader reader = new BufferedReader
|
||||
(new InputStreamReader(proc.getInputStream()));
|
||||
// Skip the first line as it is the "df" output header.
|
||||
if (reader.readLine() != null ) {
|
||||
String prevMountPoint = null, mountPoint = null;
|
||||
while ((mountPoint = reader.readLine()) != null) {
|
||||
if (prevMountPoint != null &&
|
||||
mountPoint.equals(prevMountPoint)) {
|
||||
throw new RuntimeException
|
||||
("System configuration error: " +
|
||||
"duplicate mount point " + mountPoint +
|
||||
" detected");
|
||||
}
|
||||
prevMountPoint = mountPoint;
|
||||
}
|
||||
}
|
||||
public static boolean areMountPointsAccessibleAndUnique() {
|
||||
if (IS_WINDOWS) return true;
|
||||
|
||||
try {
|
||||
proc.waitFor(90, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
try {
|
||||
int exitValue = proc.exitValue();
|
||||
if (exitValue != 0) {
|
||||
System.err.printf("df process exited with %d != 0%n",
|
||||
exitValue);
|
||||
final AtomicBoolean areMountPointsOK = new AtomicBoolean(true);
|
||||
Thread thr = new Thread(() -> {
|
||||
try {
|
||||
Process proc = new ProcessBuilder("df").start();
|
||||
BufferedReader reader = new BufferedReader
|
||||
(new InputStreamReader(proc.getInputStream()));
|
||||
// Skip the first line as it is the "df" output header.
|
||||
if (reader.readLine() != null ) {
|
||||
Set mountPoints = new HashSet();
|
||||
String mountPoint = null;
|
||||
while ((mountPoint = reader.readLine()) != null) {
|
||||
if (!mountPoints.add(mountPoint)) {
|
||||
System.err.printf
|
||||
("Config error: duplicate mount point %s%n",
|
||||
mountPoint);
|
||||
areMountPointsOK.set(false);
|
||||
break;
|
||||
}
|
||||
} catch (IllegalThreadStateException ignored) {
|
||||
System.err.println("df command apparently hung");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
proc.waitFor(90, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
try {
|
||||
int exitValue = proc.exitValue();
|
||||
if (exitValue != 0) {
|
||||
System.err.printf("df process exited with %d != 0%n",
|
||||
exitValue);
|
||||
areMountPointsOK.set(false);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
};
|
||||
} catch (IllegalThreadStateException ignored) {
|
||||
System.err.println("df command apparently hung");
|
||||
areMountPointsOK.set(false);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
};
|
||||
});
|
||||
|
||||
final AtomicReference throwableReference =
|
||||
new AtomicReference<Throwable>();
|
||||
thr.setUncaughtExceptionHandler(
|
||||
new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
throwableReference.set(e);
|
||||
}
|
||||
});
|
||||
|
||||
final AtomicReference throwableReference =
|
||||
new AtomicReference<Throwable>();
|
||||
thr.setUncaughtExceptionHandler(
|
||||
new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
throwableReference.set(e);
|
||||
}
|
||||
});
|
||||
thr.start();
|
||||
try {
|
||||
thr.join(120*1000L);
|
||||
} catch (InterruptedException ie) {
|
||||
throw new RuntimeException(ie);
|
||||
}
|
||||
|
||||
thr.start();
|
||||
try {
|
||||
thr.join(120*1000L);
|
||||
} catch (InterruptedException ie) {
|
||||
throw new RuntimeException(ie);
|
||||
}
|
||||
Throwable uncaughtException = (Throwable)throwableReference.get();
|
||||
if (uncaughtException != null) {
|
||||
throw new RuntimeException(uncaughtException);
|
||||
}
|
||||
|
||||
Throwable uncaughtException = (Throwable)throwableReference.get();
|
||||
if (uncaughtException != null) {
|
||||
throw new RuntimeException(uncaughtException);
|
||||
}
|
||||
|
||||
if (thr.isAlive()) {
|
||||
throw new RuntimeException("df thread did not join in time");
|
||||
}
|
||||
if (thr.isAlive()) {
|
||||
throw new RuntimeException("df thread did not join in time");
|
||||
}
|
||||
|
||||
return areMountPointsOK.get();
|
||||
|
Loading…
Reference in New Issue
Block a user