From 2f2594d5d07826dcc100739d366788fe434b3375 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Thu, 23 Jan 2020 08:43:22 -0800 Subject: [PATCH] 8231515: [Graal] Crash during exception throwing in InterpreterRuntime::resolve_invoke Reviewed-by: kvn, dlong, iveresov --- src/hotspot/share/aot/aotCodeHeap.cpp | 1 + src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 1 + .../share/jvmci/jvmciCompilerToVMInit.cpp | 2 + src/hotspot/share/jvmci/jvmciRuntime.cpp | 15 +- src/hotspot/share/jvmci/jvmciRuntime.hpp | 6 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + .../jaotc/binformat/BinaryContainer.java | 10 +- .../compiler/core/test/SubprocessTest.java | 7 + .../compiler/core/gen/DebugInfoBuilder.java | 21 ++- .../compiler/core/gen/NodeLIRBuilder.java | 17 +-- .../aarch64/AArch64HotSpotBackend.java | 2 +- .../AArch64HotSpotDeoptimizeCallerOp.java | 4 +- .../aarch64/AArch64HotSpotDeoptimizeOp.java | 4 +- ...otSpotDeoptimizeWithExceptionCallerOp.java | 68 +++++++++ .../aarch64/AArch64HotSpotEpilogueOp.java | 4 +- .../aarch64/AArch64HotSpotLIRGenerator.java | 6 + .../hotspot/amd64/AMD64DeoptimizeOp.java | 4 +- .../hotspot/amd64/AMD64HotSpotBackend.java | 2 +- .../amd64/AMD64HotSpotDeoptimizeCallerOp.java | 4 +- ...otSpotDeoptimizeWithExceptionCallerOp.java | 75 ++++++++++ .../amd64/AMD64HotSpotLIRGenerator.java | 5 + .../hotspot/sparc/SPARCDeoptimizeOp.java | 4 +- .../hotspot/sparc/SPARCHotSpotBackend.java | 2 +- .../sparc/SPARCHotSpotDeoptimizeCallerOp.java | 4 +- ...otSpotDeoptimizeWithExceptionCallerOp.java | 77 ++++++++++ .../sparc/SPARCHotSpotLIRGenerator.java | 6 + .../test/HotSpotDeoptExplicitExceptions.java | 82 +++++++++++ .../test/HotSpotDeoptPostExceptions.java | 72 ++++++++++ .../hotspot/GraalHotSpotVMConfig.java | 5 +- .../hotspot/HotSpotDebugInfoBuilder.java | 41 +++++- .../compiler/hotspot/HotSpotHostBackend.java | 9 +- .../compiler/hotspot/HotSpotLIRGenerator.java | 12 ++ .../meta/DefaultHotSpotLoweringProvider.java | 8 +- .../meta/HotSpotHostForeignCallsProvider.java | 12 +- .../hotspot/meta/HotSpotNodePlugin.java | 60 +++++--- .../DeoptimizeWithExceptionInCallerNode.java | 63 ++++++++ .../hotspot/replacements/FastNotifyNode.java | 3 +- .../hotspot/stubs/CreateExceptionStub.java | 53 +++++-- .../graalvm/compiler/hotspot/stubs/Stub.java | 4 +- .../graalvm/compiler/java/BytecodeParser.java | 22 ++- .../graalvm/compiler/nodes/FrameState.java | 4 + .../nodes/extended/BytecodeExceptionNode.java | 13 +- .../nodes/extended/ForeignCallNode.java | 2 +- .../nodes/graphbuilderconf/NodePlugin.java | 6 +- .../test/ArrayStoreBytecodeExceptionTest.java | 34 +---- .../test/BytecodeExceptionTest.java | 25 ++-- .../test/ClassCastBytecodeExceptionTest.java | 136 ++++++++++-------- .../test/IndexOobBytecodeExceptionTest.java | 39 +---- .../test/NullBytecodeExceptionTest.java | 32 +---- 49 files changed, 834 insertions(+), 255 deletions(-) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptExplicitExceptions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptPostExceptions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeWithExceptionInCallerNode.java diff --git a/src/hotspot/share/aot/aotCodeHeap.cpp b/src/hotspot/share/aot/aotCodeHeap.cpp index 0287a42bcf2..91569d2b70d 100644 --- a/src/hotspot/share/aot/aotCodeHeap.cpp +++ b/src/hotspot/share/aot/aotCodeHeap.cpp @@ -465,6 +465,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()); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index d85fc61018c..6ddc6cd4854 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -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; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 3040272b9bc..e508be9f8bb 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -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(); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index d4a29f6ee95..1aa470d5103 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -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)) diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index 155000aa9ab..27e7abb2257 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -332,10 +332,10 @@ class JVMCIRuntime: public CHeapObj { 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); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 6721b800fac..677c7e2833d 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -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) \ diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index 0c35a871245..451669efd07 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -36,15 +36,16 @@ 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"}, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java index 82e51665147..167b96431b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java @@ -51,7 +51,14 @@ public void launchSubprocess(Runnable runnable) throws InterruptedException, IOE 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); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java index dc1e9d25fbd..21c8f20469d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java @@ -41,6 +41,7 @@ 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 DebugInfoBuilder(NodeValueMap nodeValueMap, DebugContext debug) { protected final Queue 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 LIRFrameState build(FrameState topState, LabelRef exceptionEdge) { 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 @@ protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame f 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 @@ protected BytecodeFrame computeFrameForState(FrameState state) { BytecodeFrame caller = null; if (state.outerFrameState() != null) { - caller = computeFrameForState(state.outerFrameState()); + caller = computeFrameForState(node, state.outerFrameState()); } if (!state.canProduceBytecodeFrame()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java index aa37a2a8140..474799fbe52 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java @@ -104,6 +104,7 @@ 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 LIRFrameState state(DeoptimizingNode deopt) { 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 void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, Abstrac @Override public void visitFullInfopointNode(FullInfopointNode i) { - append(new FullInfopointOp(stateFor(i.getState()), i.getReason())); + append(new FullInfopointOp(stateFor(i, i.getState()), i.getReason())); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java index 5416a641823..8415bc763d0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java @@ -390,7 +390,7 @@ private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler 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 { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java index bb0f9302ed8..a69adfaf7f7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java @@ -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 AArch64HotSpotDeoptimizeCallerOp(GraalHotSpotVMConfig config) { @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)); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java index c754fc3460b..896021927aa 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java @@ -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 AArch64HotSpotDeoptimizeOp(LIRFrameState info) { @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); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java new file mode 100644 index 00000000000..0dba0e47f2b --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java @@ -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 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)); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java index 5a9f913b906..71957b74deb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java @@ -53,8 +53,8 @@ */ abstract class AArch64HotSpotEpilogueOp extends AArch64BlockEndOp { - private final GraalHotSpotVMConfig config; - private final Register thread; + protected final GraalHotSpotVMConfig config; + protected final Register thread; protected AArch64HotSpotEpilogueOp(LIRInstructionClass c, GraalHotSpotVMConfig config, Register thread) { super(c); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java index 5fd5081ef41..e12eb72b71d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java @@ -399,6 +399,12 @@ public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReas 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); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java index b371ac890e3..4871d96e0c9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java @@ -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); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 33cac04a512..b5e0f5f1b1b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -328,7 +328,7 @@ public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationRes 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 diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java index 76885c36dee..2a30fee2de5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java @@ -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 @@ protected AMD64HotSpotDeoptimizeCallerOp() { @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)); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java new file mode 100644 index 00000000000..3ed7d957e05 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java @@ -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 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)); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java index 938f0c30cbf..ef8d42f2c30 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java @@ -544,6 +544,11 @@ public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReas append(new AMD64HotSpotDeoptimizeCallerOp()); } + @Override + public void emitDeoptimizeWithExceptionInCaller(Value exception) { + append(new AMD64HotSpotDeoptimizeWithExceptionCallerOp(config, exception)); + } + @Override public void beforeRegisterAllocation() { super.beforeRegisterAllocation(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java index a5568409371..ee2edd88b27 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java @@ -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 @@ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { // [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); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java index 0c45c57a5b5..feb7b125b30 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java @@ -349,7 +349,7 @@ public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod i 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 diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java index bbb5f0c3a3f..19464a529d0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java @@ -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 @@ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 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); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java new file mode 100644 index 00000000000..a250f2f6533 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java @@ -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 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)); + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java index ae48f464643..30e1c9bac19 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java @@ -238,6 +238,12 @@ public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReas 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(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptExplicitExceptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptExplicitExceptions.java new file mode 100644 index 00000000000..1a0457825ea --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptExplicitExceptions.java @@ -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 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(); + } + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptPostExceptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptPostExceptions.java new file mode 100644 index 00000000000..e5092bcefac --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotDeoptPostExceptions.java @@ -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); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index ec8ceb3c2f5..b6e7dc37f41 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -620,8 +620,9 @@ public int threadTlabPfTopOffset() { 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; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java index 66384cebf30..8ff4f69ca18 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java @@ -31,13 +31,19 @@ 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 @@ protected JavaValue computeLockValue(FrameState state, int lockIndex) { } @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; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java index d0e5cea68ef..019e3df9557 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java @@ -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); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java index c716464fce9..c93300622c2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java @@ -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}. * diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index cddc6d85528..e3e048d610a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -722,7 +722,13 @@ private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) { 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); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index 1c562038703..d996e04b5f3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -74,10 +74,11 @@ 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 @@ private void registerArrayCopy(JavaKind kind, 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) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java index 460dd41e7ef..2f79af1d168 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java @@ -27,6 +27,9 @@ 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.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.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 @@ * */ 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 HotSpotPostOnExceptions = new OptionKey<>(false); + } + private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe(); protected final WordOperationPlugin wordOperationPlugin; private final GraalHotSpotVMConfig config; @@ -209,35 +221,39 @@ public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, Resolve } @Override - public FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded) { + public FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded, Supplier 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; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeWithExceptionInCallerNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeWithExceptionInCallerNode.java new file mode 100644 index 00000000000..1d5c0af577c --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeWithExceptionInCallerNode.java @@ -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 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); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java index db9b4545726..ae301c92252 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java @@ -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.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 TYPE = NodeClass.create(FastNotifyNode.class); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java index 366eaba00f2..7bfe1ba366e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java @@ -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.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 @@ */ 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 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 @@ protected static Object createException(Register threadRegister, Class 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 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 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 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", 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 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()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java index 6c421b3c4a9..73bf27398ff 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java @@ -30,7 +30,7 @@ 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 @@ private boolean checkStubInvariants(CompilationResult compResult) { 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; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index 40643c70b86..f5768c9f842 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -1321,10 +1321,10 @@ private AbstractBeginNode handleException(ValueNode exceptionObject, int bci, bo 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 @@ private AbstractBeginNode handleException(ValueNode exceptionObject, int bci, bo 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 @@ private AbstractBeginNode emitBytecodeExceptionCheck(LogicNode condition, boolea 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 BailoutException bailout(String string) { } 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 boolean needsExplicitException() { @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); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java index 0a907cfb509..3b2e8d22d8a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java @@ -351,6 +351,10 @@ public FrameState duplicateModified(JavaKind popKind, JavaKind pushedSlotKind, V 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 diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java index 1d71cb5f156..c3697820d92 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java @@ -38,6 +38,7 @@ 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.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 LocationIdentity getKilledLocationIdentity() { @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 void lower(LoweringTool tool) { public NodeInputList 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); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java index 6705dfbae51..2edf82e386c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java @@ -218,7 +218,7 @@ public void computeStateDuring(FrameState currentStateAfter) { (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; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java index 46f532d9d2e..bfeae84ebe1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java @@ -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 @@ default boolean handleNewMultiArray(GraphBuilderContext b, ResolvedJavaType type * * @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 frameStateFunction) { return afterExceptionLoaded; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java index 47a9b3b9346..6fc5eb510c9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java @@ -33,39 +33,11 @@ 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 static Collection data() { @Test public void testArrayStoreException() { - test("arrayStoreSnippet", object); + test("arrayStoreSnippet", new ArrayStoreBytecodeExceptionTest[1], object); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java index 6f3070dca00..3934762b51f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java @@ -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); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java index e3a0712e4b8..611fea7fba9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java @@ -27,6 +27,7 @@ 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.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 static Collection data() { } 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 void testCastToDouble() { } 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 void testCastToByteArray() { } 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 void testCastToStringArray() { } 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 diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java index 37ad0a291ef..6a117620051 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java @@ -27,47 +27,19 @@ 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 static Collection data() { @Test public void testOutOfBoundsException() { - test("oobSnippet", index, Exceptions.empty.length); + Object[] empty = new Object[0]; + test("oobSnippet", empty, index, empty.length); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java index a5da10e35cf..1ffce991217 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java @@ -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); } }