This commit is contained in:
Jesper Wilhelmsson 2020-01-23 22:59:49 +01:00
commit c6c828fa6e
52 changed files with 903 additions and 325 deletions

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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();

View File

@ -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))

View File

@ -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);

View File

@ -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) \

View File

@ -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"},

View File

@ -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);
}
}

View File

@ -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()) {

View File

@ -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

View File

@ -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 {

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);

View File

@ -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));
}
}
}

View File

@ -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();

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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}.
*

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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());

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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(),

View File

@ -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();