From 089f83703aab9172f1e51829aa8adce3a272c4bb Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Fri, 16 Mar 2018 22:59:32 -0700 Subject: [PATCH] 8198969: Update Graal Reviewed-by: kvn --- make/CompileToolsHotspot.gmk | 1 + .../compiler/asm/amd64/AMD64Assembler.java | 145 ++++- .../bytecode/BytecodeDisassembler.java | 57 ++ .../compiler/code/DisassemblerProvider.java | 2 +- .../compiler/core/amd64/AMD64AddressNode.java | 3 +- .../amd64/AMD64ArithmeticLIRGenerator.java | 85 ++- .../core/amd64/AMD64LIRGenerator.java | 20 + .../core/amd64/AMD64NodeLIRBuilder.java | 31 + .../compiler/core/common/GraalOptions.java | 8 +- .../alloc/BiDirectionalTraceBuilder.java | 36 +- .../alloc/UniDirectionalTraceBuilder.java | 40 +- .../core/common/type/AbstractObjectStamp.java | 2 - .../compiler/core/common/type/FloatStamp.java | 98 ++- .../core/common/type/IntegerStamp.java | 101 ++- .../core/common/type/StampFactory.java | 4 + .../core/common/util/UnsignedLong.java | 98 +++ .../core/test/BasePhaseBinaryGraphTest.java | 63 ++ .../core/test/ConditionalNodeTest.java | 107 ++++ .../compiler/core/test/CountedLoopTest.java | 294 +++++++-- .../compiler/core/test/GraalCompilerTest.java | 30 +- .../compiler/core/test/GraphEncoderTest.java | 3 +- .../core/test/SwitchDyingLoopTest.java | 90 +++ .../test/TrivialInliningExplosionTest.java | 6 +- .../compiler/core/test/UnsignedLongTest.java | 139 ++++ .../graalvm/compiler/core/GraalCompiler.java | 1 + .../compiler/core/gen/NodeLIRBuilder.java | 5 + .../compiler/core/phases/HighTier.java | 7 +- .../graalvm/compiler/core/target/Backend.java | 25 +- .../.checkstyle_checks.xml | 2 +- .../src/org/graalvm/compiler/graph/Graph.java | 46 +- .../graph/InlineCacheGuardPosition.java | 79 +++ .../src/org/graalvm/compiler/graph/Node.java | 20 +- .../org/graalvm/compiler/graph/NodeClass.java | 14 +- .../compiler/graph/NodeSourcePosition.java | 188 +++++- .../graph/SourceLanguagePosition.java | 44 ++ .../SourceLanguagePositionProvider.java} | 21 +- .../aarch64/AArch64HotSpotBackend.java | 28 +- .../aarch64/AArch64HotSpotDeoptimizeOp.java | 4 +- .../hotspot/aarch64/AArch64HotSpotMove.java | 24 +- .../hotspot/amd64/test/StubAVXTest.java | 5 + .../amd64/AMD64HotSpotAddressLowering.java | 2 +- .../amd64/AMD64HotSpotLIRGenerator.java | 6 +- ...RGenerator.java => AMD64HotSpotMaths.java} | 48 +- .../hotspot/sparc/SPARCHotSpotMove.java | 15 +- .../hotspot/test/CompileTheWorld.java | 3 +- .../test/HotSpotLazyInitializationTest.java | 75 +++ .../hotspot/CompilerConfigurationFactory.java | 62 ++ .../hotspot/GraalHotSpotVMConfig.java | 14 +- .../compiler/hotspot/HotSpotBackend.java | 2 +- .../hotspot/HotSpotCompiledCodeBuilder.java | 48 +- .../hotspot/HotSpotGraalCompilerFactory.java | 80 ++- .../compiler/hotspot/NodeCostDumpUtil.java | 10 +- .../lir/VerifyMaxRegisterSizePhase.java | 77 +++ .../HotSpotClassInitializationPlugin.java | 49 ++ .../meta/HotSpotGraphBuilderPlugins.java | 2 +- .../meta/HotSpotInvocationPlugins.java | 34 +- .../hotspot/meta/HotSpotSuitesProvider.java | 11 +- .../hotspot/phases/aot/AOTInliningPolicy.java | 12 +- .../replacements/AssertionSnippets.java | 2 +- .../replacements/HashCodeSnippets.java | 2 +- .../LoadExceptionObjectSnippets.java | 2 +- .../hotspot/replacements/MonitorSnippets.java | 8 +- .../replacements/NewObjectSnippets.java | 12 +- .../hotspot/replacements/ObjectCloneNode.java | 2 +- .../replacements/StringToBytesSnippets.java | 2 +- .../replacements/UnsafeLoadSnippets.java | 2 +- .../replacements/WriteBarrierSnippets.java | 14 +- .../aot/ResolveConstantSnippets.java | 12 +- .../arraycopy/ArrayCopySnippets.java | 2 +- .../ProbabilisticProfileSnippets.java | 4 +- .../profiling/ProfileSnippets.java | 4 +- .../hotspot/stubs/ForeignCallStub.java | 43 +- .../graalvm/compiler/java/BytecodeParser.java | 364 ++++++----- .../compiler/java/BytecodeParserOptions.java | 2 +- .../compiler/java/FrameStateBuilder.java | 28 +- .../src/org/graalvm/compiler/jtt/JTTTest.java | 59 +- .../compiler/jtt/hotpath/HP_series.java | 21 +- .../graalvm/compiler/jtt/lang/Math_abs.java | 11 +- .../graalvm/compiler/jtt/lang/Math_cos.java | 11 +- .../graalvm/compiler/jtt/lang/Math_exp.java | 18 +- .../graalvm/compiler/jtt/lang/Math_log.java | 11 +- .../graalvm/compiler/jtt/lang/Math_pow.java | 44 +- .../graalvm/compiler/jtt/lang/Math_sin.java | 11 +- .../graalvm/compiler/jtt/lang/Math_sqrt.java | 11 +- .../graalvm/compiler/jtt/lang/Math_tan.java | 11 +- .../graalvm/compiler/jtt/lang/UnaryMath.java | 68 ++ .../compiler/lir/aarch64/AArch64Call.java | 16 +- .../lir/amd64/AMD64ArrayCompareToOp.java | 595 ++++++++++++++++++ .../compiler/lir/amd64/AMD64LFenceOp.java | 42 ++ .../graalvm/compiler/lir/amd64/AMD64Move.java | 33 +- .../compiler/lir/LIRInstructionClass.java | 6 +- .../lir/alloc/trace/GlobalLivenessInfo.java | 10 +- .../lir/alloc/trace/TraceAssertions.java | 69 ++ .../trace/TraceGlobalMoveResolutionPhase.java | 72 ++- .../compiler/lir/alloc/trace/TraceUtil.java | 13 - .../alloc/trace/TrivialTraceAllocator.java | 76 +-- .../lir/alloc/trace/bu/BottomUpAllocator.java | 13 +- .../TraceLinearScanLifetimeAnalysisPhase.java | 47 +- .../compiler/lir/gen/LIRGeneratorTool.java | 7 +- .../compiler/lir/phases/LIRPhaseSuite.java | 7 + .../org/graalvm/compiler/lir/ssa/SSAUtil.java | 22 + .../compiler/loop/BasicInductionVariable.java | 9 +- .../compiler/loop/CountedLoopInfo.java | 105 ++-- .../compiler/loop/DefaultLoopPolicies.java | 16 +- .../graalvm/compiler/loop/LoopFragment.java | 60 +- .../compiler/loop/LoopFragmentInside.java | 52 +- .../org/graalvm/compiler/loop/MathUtil.java | 23 +- .../compiler/nodes/test/IntegerStampTest.java | 12 + .../test/PrimitiveStampBoundaryTest.java | 26 +- .../nodes/AbstractFixedGuardNode.java | 52 +- .../org/graalvm/compiler/nodes/BeginNode.java | 14 +- .../compiler/nodes/DeoptimizeNode.java | 14 +- .../graalvm/compiler/nodes/DynamicPiNode.java | 40 +- .../graalvm/compiler/nodes/EncodedGraph.java | 30 +- .../compiler/nodes/FixedGuardNode.java | 18 +- .../graalvm/compiler/nodes/FrameState.java | 2 +- .../graalvm/compiler/nodes/GraphDecoder.java | 20 +- .../graalvm/compiler/nodes/GraphEncoder.java | 8 +- .../org/graalvm/compiler/nodes/GuardNode.java | 10 +- .../graalvm/compiler/nodes/InliningLog.java | 457 ++++++++------ .../org/graalvm/compiler/nodes/Invokable.java | 87 +++ .../org/graalvm/compiler/nodes/Invoke.java | 8 +- .../graalvm/compiler/nodes/InvokeNode.java | 10 + .../nodes/InvokeWithExceptionNode.java | 10 + .../graalvm/compiler/nodes/LoopExitNode.java | 3 + .../org/graalvm/compiler/nodes/PiNode.java | 2 +- .../nodes/StaticDeoptimizingNode.java | 15 + .../compiler/nodes/StructuredGraph.java | 48 +- .../compiler/nodes/calc/CompareNode.java | 4 +- .../compiler/nodes/calc/ConditionalNode.java | 6 +- .../nodes/calc/IntegerConvertNode.java | 9 + .../nodes/calc/IntegerLowerThanNode.java | 18 +- .../nodes/extended/IntegerSwitchNode.java | 33 +- .../ClassInitializationPlugin.java | 6 + .../GraphBuilderConfiguration.java | 3 +- .../graphbuilderconf/InlineInvokePlugin.java | 24 +- .../graphbuilderconf/IntrinsicContext.java | 45 +- .../nodes/java/InstanceOfDynamicNode.java | 25 +- .../compiler/nodes/spi/Replacements.java | 15 +- .../common/ConditionalEliminationPhase.java | 76 ++- .../common/ConvertDeoptimizeToGuardPhase.java | 58 +- .../phases/common/NodeCounterPhase.java | 50 ++ .../phases/common/inlining/InliningUtil.java | 257 ++++++-- .../inlining/info/AbstractInlineInfo.java | 2 +- .../common/inlining/info/elem/Inlineable.java | 4 +- .../inlining/info/elem/InlineableGraph.java | 16 +- .../inlining/policy/GreedyInliningPolicy.java | 16 +- .../InlineMethodSubstitutionsPolicy.java | 2 +- .../common/inlining/walker/InliningData.java | 22 +- .../graalvm/compiler/phases/PhaseSuite.java | 7 + .../phases/contract/VerifyNodeCosts.java | 8 +- .../compiler/printer/BinaryGraphPrinter.java | 18 +- .../compiler/printer/GraphPrinter.java | 6 +- .../printer/GraphPrinterDumpHandler.java | 5 +- .../AArch64FloatArithmeticSnippets.java | 2 +- .../AArch64IntegerArithmeticSnippets.java | 2 +- .../amd64/AMD64ConvertSnippets.java | 2 +- .../amd64/AMD64GraphBuilderPlugins.java | 31 +- .../amd64/AMD64StringLatin1Substitutions.java | 59 ++ .../amd64/AMD64StringSubstitutions.java | 15 + .../amd64/AMD64StringUTF16Substitutions.java | 63 ++ .../test/MethodSubstitutionTest.java | 2 +- .../replacements/test/PEGraphDecoderTest.java | 4 +- .../replacements/test/SnippetsTest.java | 2 +- .../test/StandardMethodSubstitutionsTest.java | 5 +- .../test/StringCompareToTest.java | 115 ++++ .../test/StringSubstitutionsTest.java | 5 +- .../compiler/replacements/test/WordTest.java | 2 +- .../compiler/replacements/BoxingSnippets.java | 6 +- .../replacements/CachingPEGraphDecoder.java | 16 +- .../ConstantStringIndexOfSnippets.java | 2 +- .../compiler/replacements/GraphKit.java | 74 ++- .../InlineDuringParsingPlugin.java | 21 +- .../InstanceOfSnippetsTemplates.java | 2 +- .../replacements/IntrinsicGraphBuilder.java | 19 +- .../compiler/replacements/PEGraphDecoder.java | 98 ++- .../replacements/ReplacementsImpl.java | 46 +- .../replacements/SnippetCounterNode.java | 2 +- .../replacements/SnippetTemplate.java | 102 +-- .../StandardGraphBuilderPlugins.java | 19 + .../replacements/StringSubstitutions.java | 2 +- .../classfile/ClassfileBytecodeProvider.java | 4 +- .../nodes/ArrayCompareToNode.java | 139 ++++ .../replacements/nodes/MacroNode.java | 29 +- .../nodes/MacroStateSplitNode.java | 2 +- .../serviceprovider/GraalServices.java | 14 +- .../compiler/serviceprovider/JDK9Method.java | 127 ++-- .../src/org/graalvm/graphio/ProtocolImpl.java | 12 +- .../src/micro/benchmarks/StringBenchmark.java | 7 + 189 files changed, 5747 insertions(+), 1526 deletions(-) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsignedLong.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BasePhaseBinaryGraphTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsignedLongTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InlineCacheGuardPosition.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java => org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePositionProvider.java} (77%) rename src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/{AMD64HotSpotArithmeticLIRGenerator.java => AMD64HotSpotMaths.java} (55%) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/VerifyMaxRegisterSizePhase.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LFenceOp.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAssertions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java diff --git a/make/CompileToolsHotspot.gmk b/make/CompileToolsHotspot.gmk index 54ab9ae0dfb..79468ad62b2 100644 --- a/make/CompileToolsHotspot.gmk +++ b/make/CompileToolsHotspot.gmk @@ -120,6 +120,7 @@ ifeq ($(INCLUDE_GRAAL), true) SRC := \ $(SRC_DIR)/org.graalvm.word/src \ $(SRC_DIR)/org.graalvm.collections/src \ + $(SRC_DIR)/org.graalvm.compiler.bytecode/src \ $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \ $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \ $(SRC_DIR)/org.graalvm.compiler.code/src \ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java index 2bdbabcd46e..6bc4f378dc2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java @@ -195,11 +195,6 @@ public class AMD64Assembler extends Assembler { private static final int VEX_W = 0x80; } - private static class AvxVectorLen { - private static final int AVX_128bit = 0x0; - private static final int AVX_256bit = 0x1; - } - private static class VexSimdPrefix { private static final int VEX_SIMD_NONE = 0x0; private static final int VEX_SIMD_66 = 0x1; @@ -208,11 +203,44 @@ public class AMD64Assembler extends Assembler { } private static class VexOpcode { + private static final int VEX_OPCODE_NONE = 0x0; private static final int VEX_OPCODE_0F = 0x1; private static final int VEX_OPCODE_0F_38 = 0x2; private static final int VEX_OPCODE_0F_3A = 0x3; } + public static class AvxVectorLen { + public static final int AVX_128bit = 0x0; + public static final int AVX_256bit = 0x1; + public static final int AVX_512bit = 0x2; + public static final int AVX_NoVec = 0x4; + } + + public static class EvexTupleType { + public static final int EVEX_FV = 0; + public static final int EVEX_HV = 4; + public static final int EVEX_FVM = 6; + public static final int EVEX_T1S = 7; + public static final int EVEX_T1F = 11; + public static final int EVEX_T2 = 13; + public static final int EVEX_T4 = 15; + public static final int EVEX_T8 = 17; + public static final int EVEX_HVM = 18; + public static final int EVEX_QVM = 19; + public static final int EVEX_OVM = 20; + public static final int EVEX_M128 = 21; + public static final int EVEX_DUP = 22; + public static final int EVEX_ETUP = 23; + } + + public static class EvexInputSizeInBits { + public static final int EVEX_8bit = 0; + public static final int EVEX_16bit = 1; + public static final int EVEX_32bit = 2; + public static final int EVEX_64bit = 3; + public static final int EVEX_NObit = 4; + } + private AMD64InstructionAttr curAttributes; AMD64InstructionAttr getCurAttributes() { @@ -873,6 +901,7 @@ public class AMD64Assembler extends Assembler { opc = VexOpcode.VEX_OPCODE_0F_3A; break; default: + opc = VexOpcode.VEX_OPCODE_NONE; isSimd = false; break; } @@ -1770,6 +1799,13 @@ public class AMD64Assembler extends Assembler { emitOperandHelper(dst, src, 0); } + public final void bsfq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding(), src.encoding()); + emitByte(0x0F); + emitByte(0xBC); + emitByte(0xC0 | encode); + } + public final void bsrl(Register dst, Register src) { int encode = prefixAndEncode(dst.encoding(), src.encoding()); emitByte(0x0F); @@ -1857,6 +1893,26 @@ public class AMD64Assembler extends Assembler { emitByte(0xC0 | encode); } + public final void evmovdquq(Register dst, AMD64Address src, int vectorLen) { + assert supports(CPUFeature.AVX512F); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true, target); + attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit); + attributes.setIsEvexInstruction(); + vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6F); + emitOperandHelper(dst, src, 0); + } + + public final void evpcmpeqb(Register kdst, Register nds, AMD64Address src, int vectorLen) { + assert supports(CPUFeature.AVX512BW); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target); + attributes.setIsEvexInstruction(); + attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit); + vexPrefix(src, nds, kdst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x74); + emitOperandHelper(kdst, src, 0); + } + public final void hlt() { emitByte(0xF4); } @@ -1982,6 +2038,32 @@ public class AMD64Assembler extends Assembler { } } + // This instruction produces ZF or CF flags + public final void kortestql(Register src1, Register src2) { + assert supports(CPUFeature.AVX512BW); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target); + int encode = vexPrefixAndEncode(src1, Register.None, src2, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x98); + emitByte(0xC0 | encode); + } + + public final void kmovql(Register dst, Register src) { + assert supports(CPUFeature.AVX512BW); + if (src.getRegisterCategory().equals(AMD64.MASK)) { + // kmovql(KRegister dst, KRegister src) + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target); + int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x90); + emitByte(0xC0 | encode); + } else { + // kmovql(KRegister dst, Register src) + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target); + int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x92); + emitByte(0xC0 | encode); + } + } + public final void lead(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x8D); @@ -2050,6 +2132,15 @@ public class AMD64Assembler extends Assembler { emitOperandHelper(dst, src, 0); } + /** + * @param wide use 4 byte encoding for displacements that would normally fit in a byte + */ + public final void movl(Register dst, AMD64Address src, boolean wide) { + prefix(src, dst); + emitByte(0x8B); + emitOperandHelper(dst, src, wide, 0); + } + public final void movl(AMD64Address dst, int imm32) { prefix(dst); emitByte(0xC7); @@ -2291,6 +2382,10 @@ public class AMD64Assembler extends Assembler { NOT.emit(this, DWORD, dst); } + public final void notq(Register dst) { + NOT.emit(this, QWORD, dst); + } + @Override public final void ensureUniquePC() { nop(); @@ -2540,7 +2635,7 @@ public class AMD64Assembler extends Assembler { emitByte(0xC0 | encode); } - void pcmpestri(Register dst, AMD64Address src, int imm8) { + public final void pcmpestri(Register dst, AMD64Address src, int imm8) { assert supports(CPUFeature.SSE4_2); AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes); @@ -2549,7 +2644,7 @@ public class AMD64Assembler extends Assembler { emitByte(imm8); } - void pcmpestri(Register dst, Register src, int imm8) { + public final void pcmpestri(Register dst, Register src, int imm8) { assert supports(CPUFeature.SSE4_2); AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes); @@ -2558,6 +2653,26 @@ public class AMD64Assembler extends Assembler { emitByte(imm8); } + public final void pmovzxbw(Register dst, AMD64Address src) { + assert supports(CPUFeature.SSE4_2); + // XXX legacy_mode should be: _legacy_mode_bw + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target); + attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_HVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit); + simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes); + emitByte(0x30); + emitOperandHelper(dst, src, 0); + } + + public final void vpmovzxbw(Register dst, AMD64Address src, int vectorLen) { + assert supports(CPUFeature.AVX); + // XXX legacy_mode should be: _legacy_mode_bw + AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target); + attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_HVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit); + vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes); + emitByte(0x30); + emitOperandHelper(dst, src, 0); + } + public final void push(Register src) { int encode = prefixAndEncode(src.encoding); emitByte(0x50 | encode); @@ -2634,6 +2749,15 @@ public class AMD64Assembler extends Assembler { emitByte(0xC0 | encode); } + public final void vpxor(Register dst, Register nds, AMD64Address src) { + assert supports(CPUFeature.AVX); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true, target); + attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FV, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_32bit); + vexPrefix(src, nds, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xEF); + emitOperandHelper(dst, src, 0); + } + public final void pslld(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; assert dst.getRegisterCategory().equals(AMD64.XMM); @@ -3843,4 +3967,11 @@ public class AMD64Assembler extends Assembler { emitByte(0x0f); emitByte(0x0b); } + + public void lfence() { + emitByte(0x0f); + emitByte(0xae); + emitByte(0xe8); + + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java index 41e52e24482..a50059e2f4c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java @@ -321,4 +321,61 @@ public class BytecodeDisassembler { } // @formatter:on } + + public static JavaMethod getInvokedMethodAt(ResolvedJavaMethod method, int invokeBci) { + if (method.getCode() == null) { + return null; + } + ConstantPool cp = method.getConstantPool(); + BytecodeStream stream = new BytecodeStream(method.getCode()); + int opcode = stream.currentBC(); + while (opcode != Bytecodes.END) { + int bci = stream.currentBCI(); + if (bci == invokeBci) { + if (stream.nextBCI() > bci + 1) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + case INVOKESTATIC: { + int cpi = stream.readCPI(); + JavaMethod callee = cp.lookupMethod(cpi, opcode); + return callee; + } + case INVOKEINTERFACE: { + int cpi = stream.readCPI(); + JavaMethod callee = cp.lookupMethod(cpi, opcode); + return callee; + } + case INVOKEDYNAMIC: { + int cpi = stream.readCPI4(); + JavaMethod callee = cp.lookupMethod(cpi, opcode); + return callee; + } + default: + throw new InternalError(BytecodeDisassembler.disassembleOne(method, invokeBci)); + } + } + } + stream.next(); + opcode = stream.currentBC(); + } + return null; + } + + public static int getBytecodeAt(ResolvedJavaMethod method, int invokeBci) { + if (method.getCode() == null) { + return -1; + } + BytecodeStream stream = new BytecodeStream(method.getCode()); + int opcode = stream.currentBC(); + while (opcode != Bytecodes.END) { + int bci = stream.currentBCI(); + if (bci == invokeBci) { + return opcode; + } + stream.next(); + opcode = stream.currentBC(); + } + return -1; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java index 0b5f6a0d67d..7e71a4082c3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java @@ -58,7 +58,7 @@ public interface DisassemblerProvider { } /** - * Gets the name denoting the format of the disassmembly return by this object. + * Gets the name denoting the format of the disassembly returned by this object. */ String getName(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java index bd27ef756d3..922413d2698 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java @@ -25,6 +25,7 @@ package org.graalvm.compiler.core.amd64; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Simplifiable; import org.graalvm.compiler.graph.spi.SimplifierTool; @@ -72,7 +73,7 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo } public void canonicalizeIndex(SimplifierTool tool) { - if (index instanceof AddNode) { + if (index instanceof AddNode && ((IntegerStamp) index.stamp(NodeView.DEFAULT)).getBits() == 64) { AddNode add = (AddNode) index; ValueNode valX = add.getX(); if (valX instanceof PhiNode) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java index 5b442b1e3bf..ec2077d8d36 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java @@ -66,15 +66,14 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM; import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FREM; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW; import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.COS; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP; import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG; import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10; import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.SIN; import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN; -import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP; -import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW; -import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; @@ -83,10 +82,11 @@ import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; -import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.calc.FloatConvert; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.ConstantValue; @@ -107,6 +107,7 @@ import org.graalvm.compiler.lir.amd64.AMD64ShiftOp; import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp; import org.graalvm.compiler.lir.amd64.AMD64Unary; import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; +import org.graalvm.compiler.lir.gen.LIRGenerator; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; @@ -114,6 +115,7 @@ import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -122,7 +124,6 @@ import jdk.vm.ci.meta.PlatformKind; import jdk.vm.ci.meta.VMConstant; import jdk.vm.ci.meta.Value; import jdk.vm.ci.meta.ValueKind; -import jdk.vm.ci.code.TargetDescription; /** * This class implements the AMD64 specific portion of the LIR generator. @@ -131,6 +132,40 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.DWORD)); + public AMD64ArithmeticLIRGenerator(Maths maths) { + this.maths = maths == null ? new Maths() { + } : maths; + } + + private final Maths maths; + + /** + * Interface for emitting LIR for selected {@link Math} routines. A {@code null} return value + * for any method in this interface means the caller must emit the LIR itself. + */ + public interface Maths { + + @SuppressWarnings("unused") + default Variable emitLog(LIRGenerator gen, Value input, boolean base10) { + return null; + } + + @SuppressWarnings("unused") + default Variable emitCos(LIRGenerator gen, Value input) { + return null; + } + + @SuppressWarnings("unused") + default Variable emitSin(LIRGenerator gen, Value input) { + return null; + } + + @SuppressWarnings("unused") + default Variable emitTan(LIRGenerator gen, Value input) { + return null; + } + } + @Override public Variable emitNegate(Value inputVal) { AllocatableValue input = getLIRGen().asAllocatable(inputVal); @@ -1042,33 +1077,49 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen @Override public Value emitMathLog(Value input, boolean base10) { - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); - getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input), stackSlot)); + LIRGenerator gen = getLIRGen(); + Variable result = maths.emitLog(gen, input, base10); + if (result == null) { + result = gen.newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, gen.asAllocatable(input), stackSlot)); + } return result; } @Override public Value emitMathCos(Value input) { - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); - getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, getLIRGen().asAllocatable(input), stackSlot)); + LIRGenerator gen = getLIRGen(); + Variable result = maths.emitCos(gen, input); + if (result == null) { + result = gen.newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, gen.asAllocatable(input), stackSlot)); + } return result; } @Override public Value emitMathSin(Value input) { - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); - getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, getLIRGen().asAllocatable(input), stackSlot)); + LIRGenerator gen = getLIRGen(); + Variable result = maths.emitSin(gen, input); + if (result == null) { + result = gen.newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, gen.asAllocatable(input), stackSlot)); + } return result; } @Override public Value emitMathTan(Value input) { - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); - getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, getLIRGen().asAllocatable(input), stackSlot)); + LIRGenerator gen = getLIRGen(); + Variable result = maths.emitTan(gen, input); + if (result == null) { + result = gen.newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, gen.asAllocatable(input), stackSlot)); + } return result; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java index 6e7258ae62f..9abd808ab4b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java @@ -59,6 +59,7 @@ import org.graalvm.compiler.lir.SwitchStrategy; import org.graalvm.compiler.lir.Variable; import org.graalvm.compiler.lir.amd64.AMD64AddressValue; import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool; +import org.graalvm.compiler.lir.amd64.AMD64ArrayCompareToOp; import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp; import org.graalvm.compiler.lir.amd64.AMD64Binary; import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer; @@ -74,6 +75,7 @@ import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondSetOp; import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp; import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp; +import org.graalvm.compiler.lir.amd64.AMD64LFenceOp; import org.graalvm.compiler.lir.amd64.AMD64Move; import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp; import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp; @@ -489,6 +491,20 @@ public abstract class AMD64LIRGenerator extends LIRGenerator { return result; } + @Override + public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) { + LIRKind resultKind = LIRKind.value(AMD64Kind.DWORD); + RegisterValue raxRes = AMD64.rax.asValue(resultKind); + RegisterValue cnt1 = AMD64.rcx.asValue(length1.getValueKind()); + RegisterValue cnt2 = AMD64.rdx.asValue(length2.getValueKind()); + emitMove(cnt1, length1); + emitMove(cnt2, length2); + append(new AMD64ArrayCompareToOp(this, kind1, kind2, raxRes, array1, array2, cnt1, cnt2)); + Variable result = newVariable(resultKind); + emitMove(result, raxRes); + return result; + } + @Override public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); @@ -554,4 +570,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator { public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { return new AMD64ZapStackOp(zappedStack, zapValues); } + + public void emitLFence() { + append(new AMD64LFenceOp()); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java index ea5494a0844..efed030fc9d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java @@ -23,6 +23,8 @@ package org.graalvm.compiler.core.amd64; +import static org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder.Options.MitigateSpeculativeExecutionAttacks; + import org.graalvm.compiler.core.gen.NodeLIRBuilder; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRFrameState; @@ -37,6 +39,11 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op; +import org.graalvm.compiler.nodes.cfg.Block; +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 jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.meta.AllocatableValue; @@ -44,6 +51,13 @@ import jdk.vm.ci.meta.Value; public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { + public static class Options { + // @formatter:off + @Option(help = "AMD64: Emit lfence instructions at the beginning of basic blocks", type = OptionType.Expert) + public static final OptionKey MitigateSpeculativeExecutionAttacks = new OptionKey<>(false); + // @formatter:on + } + public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) { super(graph, gen, nodeMatchRules); } @@ -121,4 +135,21 @@ public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { public AMD64LIRGenerator getLIRGeneratorTool() { return (AMD64LIRGenerator) gen; } + + @Override + public void doBlockPrologue(Block block, OptionValues options) { + if (MitigateSpeculativeExecutionAttacks.getValue(options)) { + boolean hasControlSplitPredecessor = false; + for (Block b : block.getPredecessors()) { + if (b.getSuccessorCount() > 1) { + hasControlSplitPredecessor = true; + break; + } + } + boolean isStartBlock = block.getPredecessorCount() == 0; + if (hasControlSplitPredecessor || isStartBlock) { + getLIRGeneratorTool().emitLFence(); + } + } + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java index c01737e3d08..713fe7b3fb7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java @@ -259,6 +259,9 @@ public final class GraalOptions { @Option(help = "", type = OptionType.Debug) public static final OptionKey OptDevirtualizeInvokesOptimistically = new OptionKey<>(true); + @Option(help = "Track the NodeSourcePosition.", type = OptionType.Debug) + public static final OptionKey TrackNodeSourcePosition = new OptionKey<>(false); + @Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug) public static final OptionKey MatchExpressions = new OptionKey<>(true); @@ -273,8 +276,7 @@ public final class GraalOptions { @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug) public static final OptionKey TraceRA = new OptionKey<>(false); - - @Option(help = "How to trace inlining decisions, one of: None, Linear, Tree", type = OptionType.Debug) - public static final OptionKey TraceInlining = new OptionKey<>(TraceInliningMode.None); + @Option(help = "Enable tracing of inlining decision.", type = OptionType.Debug) + public static final OptionKey TraceInlining = new OptionKey<>(false); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java index f0ad0133f95..d6c1e644032 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java @@ -84,7 +84,7 @@ public final class BiDirectionalTraceBuilder { AbstractBlockBase block = worklist.pollFirst(); assert block != null; if (!processed(block)) { - Trace trace = new Trace(startTrace(debug, block)); + Trace trace = new Trace(findTrace(debug, block)); for (AbstractBlockBase traceBlock : trace.getBlocks()) { blockToTrace[traceBlock.getId()] = trace; } @@ -101,13 +101,13 @@ public final class BiDirectionalTraceBuilder { * @param debug */ @SuppressWarnings("try") - private Collection> startTrace(DebugContext debug, AbstractBlockBase block) { + private Collection> findTrace(DebugContext debug, AbstractBlockBase initBlock) { ArrayDeque> trace = new ArrayDeque<>(); - try (Indent i = debug.logAndIndent("StartTrace: %s", block)) { + try (Indent i = debug.logAndIndent("StartTrace: %s", initBlock)) { try (Indent indentFront = debug.logAndIndent("Head:")) { - for (AbstractBlockBase currentBlock = block; currentBlock != null; currentBlock = selectPredecessor(currentBlock)) { - addBlockToTrace(debug, currentBlock); - trace.addFirst(currentBlock); + for (AbstractBlockBase block = initBlock; block != null; block = selectPredecessor(block)) { + addBlockToTrace(debug, block); + trace.addFirst(block); } } /* Number head blocks. Can not do this in the loop as we go backwards. */ @@ -117,11 +117,11 @@ public final class BiDirectionalTraceBuilder { } try (Indent indentBack = debug.logAndIndent("Tail:")) { - for (AbstractBlockBase currentBlock = selectSuccessor(block); currentBlock != null; currentBlock = selectSuccessor(currentBlock)) { - addBlockToTrace(debug, currentBlock); - trace.addLast(currentBlock); + for (AbstractBlockBase block = selectSuccessor(initBlock); block != null; block = selectSuccessor(block)) { + addBlockToTrace(debug, block); + trace.addLast(block); /* This time we can number the blocks immediately as we go forwards. */ - currentBlock.setLinearScanNumber(blockNr++); + block.setLinearScanNumber(blockNr++); } } } @@ -129,18 +129,18 @@ public final class BiDirectionalTraceBuilder { return trace; } - private void addBlockToTrace(DebugContext debug, AbstractBlockBase currentBlock) { - debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); - processed.set(currentBlock.getId()); + private void addBlockToTrace(DebugContext debug, AbstractBlockBase block) { + debug.log("add %s (prob: %f)", block, block.probability()); + processed.set(block.getId()); } /** * @return The unprocessed predecessor with the highest probability, or {@code null}. */ - private AbstractBlockBase selectPredecessor(AbstractBlockBase currentBlock) { + private AbstractBlockBase selectPredecessor(AbstractBlockBase block) { AbstractBlockBase next = null; - for (AbstractBlockBase pred : currentBlock.getPredecessors()) { - if (!processed(pred) && !isBackEdge(pred, currentBlock) && (next == null || pred.probability() > next.probability())) { + for (AbstractBlockBase pred : block.getPredecessors()) { + if (!processed(pred) && !isBackEdge(pred, block) && (next == null || pred.probability() > next.probability())) { next = pred; } } @@ -155,9 +155,9 @@ public final class BiDirectionalTraceBuilder { /** * @return The unprocessed successor with the highest probability, or {@code null}. */ - private AbstractBlockBase selectSuccessor(AbstractBlockBase currentBlock) { + private AbstractBlockBase selectSuccessor(AbstractBlockBase block) { AbstractBlockBase next = null; - for (AbstractBlockBase succ : currentBlock.getSuccessors()) { + for (AbstractBlockBase succ : block.getSuccessors()) { if (!processed(succ) && (next == null || succ.probability() > next.probability())) { next = succ; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java index 42023e1c007..12f1981dafe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java @@ -33,7 +33,7 @@ import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; /** - * Computes traces by starting at a trace head and keep adding predecessors as long as possible. + * Computes traces by starting at a trace head and keep adding successors as long as possible. */ public final class UniDirectionalTraceBuilder { @@ -87,7 +87,7 @@ public final class UniDirectionalTraceBuilder { AbstractBlockBase block = worklist.poll(); assert block != null; if (!processed(block)) { - Trace trace = new Trace(startTrace(debug, block)); + Trace trace = new Trace(findTrace(debug, block)); for (AbstractBlockBase traceBlock : trace.getBlocks()) { blockToTrace[traceBlock.getId()] = trace; } @@ -102,17 +102,17 @@ public final class UniDirectionalTraceBuilder { * Build a new trace starting at {@code block}. */ @SuppressWarnings("try") - private List> startTrace(DebugContext debug, AbstractBlockBase block) { - assert checkPredecessorsProcessed(block); + private List> findTrace(DebugContext debug, AbstractBlockBase traceStart) { + assert checkPredecessorsProcessed(traceStart); ArrayList> trace = new ArrayList<>(); int blockNumber = 0; - try (Indent i = debug.logAndIndent("StartTrace: %s", block)) { - for (AbstractBlockBase currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) { - debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); - processed.set(currentBlock.getId()); - trace.add(currentBlock); - unblock(currentBlock); - currentBlock.setLinearScanNumber(blockNumber++); + try (Indent i = debug.logAndIndent("StartTrace: %s", traceStart)) { + for (AbstractBlockBase block = traceStart; block != null; block = selectNext(block)) { + debug.log("add %s (prob: %f)", block, block.probability()); + processed.set(block.getId()); + trace.add(block); + unblock(block); + block.setLinearScanNumber(blockNumber++); } } return trace; @@ -120,11 +120,7 @@ public final class UniDirectionalTraceBuilder { private boolean checkPredecessorsProcessed(AbstractBlockBase block) { for (AbstractBlockBase pred : block.getPredecessors()) { - if (!processed(pred)) { - assert false : "Predecessor unscheduled: " + pred; - return false; - } - + assert processed(pred) : "Predecessor unscheduled: " + pred; } return true; } @@ -133,8 +129,8 @@ public final class UniDirectionalTraceBuilder { * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once * the count reaches 0. */ - private void unblock(AbstractBlockBase currentBlock) { - for (AbstractBlockBase successor : currentBlock.getSuccessors()) { + private void unblock(AbstractBlockBase block) { + for (AbstractBlockBase successor : block.getSuccessors()) { if (!processed(successor)) { int blockCount = --blocked[successor.getId()]; assert blockCount >= 0; @@ -148,11 +144,11 @@ public final class UniDirectionalTraceBuilder { /** * @return The unprocessed predecessor with the highest probability, or {@code null}. */ - private AbstractBlockBase selectNext(AbstractBlockBase currentBlock) { + private AbstractBlockBase selectNext(AbstractBlockBase block) { AbstractBlockBase next = null; - for (AbstractBlockBase succ : currentBlock.getSuccessors()) { - if (!processed(succ) && (next == null || succ.probability() > next.probability())) { - next = succ; + for (AbstractBlockBase successor : block.getSuccessors()) { + if (!processed(successor) && (next == null || successor.probability() > next.probability())) { + next = successor; } } return next; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java index b84f2182adf..917cf2b9527 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java @@ -191,8 +191,6 @@ public abstract class AbstractObjectStamp extends AbstractPointerStamp { boolean joinExactType = exactType || other.exactType; if (Objects.equals(type, other.type)) { joinType = type; - } else if (type == null && other.type == null) { - joinType = null; } else if (type == null) { joinType = other.type; } else if (other.type == null) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java index b9e057ef153..5295d7c51d7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java @@ -176,11 +176,15 @@ public class FloatStamp extends PrimitiveStamp { StringBuilder str = new StringBuilder(); str.append('f'); str.append(getBits()); - str.append(nonNaN ? "!" : ""); - if (lowerBound == upperBound) { - str.append(" [").append(lowerBound).append(']'); - } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) { - str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']'); + if (hasValues()) { + str.append(nonNaN ? "!" : ""); + if (lowerBound == upperBound) { + str.append(" [").append(lowerBound).append(']'); + } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) { + str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']'); + } + } else { + str.append(""); } return str.toString(); } @@ -200,6 +204,12 @@ public class FloatStamp extends PrimitiveStamp { if (otherStamp == this) { return this; } + if (isEmpty()) { + return this; + } + if (otherStamp.isEmpty()) { + return otherStamp; + } FloatStamp other = (FloatStamp) otherStamp; assert getBits() == other.getBits(); double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max); @@ -383,6 +393,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s) { + if (s.isEmpty()) { + return s; + } FloatStamp stamp = (FloatStamp) s; Stamp folded = maybeFoldConstant(this, stamp); if (folded != null) { @@ -412,6 +425,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -454,6 +473,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -496,6 +521,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -544,6 +575,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -586,6 +623,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -615,6 +658,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s) { + if (s.isEmpty()) { + return s; + } FloatStamp stamp = (FloatStamp) s; JavaConstant constant = stamp.asConstant(); if (constant != null) { @@ -653,6 +699,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -701,6 +753,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -747,6 +805,12 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s1, Stamp s2) { + if (s1.isEmpty()) { + return s1; + } + if (s2.isEmpty()) { + return s2; + } FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp2 = (FloatStamp) s2; Stamp folded = maybeFoldConstant(this, stamp1, stamp2); @@ -789,6 +853,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s) { + if (s.isEmpty()) { + return s; + } FloatStamp stamp = (FloatStamp) s; Stamp folded = maybeFoldConstant(this, stamp); if (folded != null) { @@ -818,6 +885,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s) { + if (s.isEmpty()) { + return s; + } FloatStamp stamp = (FloatStamp) s; Stamp folded = maybeFoldConstant(this, stamp); if (folded != null) { @@ -839,6 +909,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return StampFactory.empty(JavaKind.Int); + } FloatStamp floatStamp = (FloatStamp) stamp; assert floatStamp.getBits() == 32; boolean mustHaveZero = !floatStamp.isNonNaN(); @@ -865,6 +938,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return StampFactory.empty(JavaKind.Long); + } FloatStamp floatStamp = (FloatStamp) stamp; assert floatStamp.getBits() == 32; boolean mustHaveZero = !floatStamp.isNonNaN(); @@ -891,6 +967,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return StampFactory.empty(JavaKind.Int); + } FloatStamp floatStamp = (FloatStamp) stamp; assert floatStamp.getBits() == 64; boolean mustHaveZero = !floatStamp.isNonNaN(); @@ -917,6 +996,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return StampFactory.empty(JavaKind.Long); + } FloatStamp floatStamp = (FloatStamp) stamp; assert floatStamp.getBits() == 64; boolean mustHaveZero = !floatStamp.isNonNaN(); @@ -943,6 +1025,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return StampFactory.empty(JavaKind.Double); + } FloatStamp floatStamp = (FloatStamp) stamp; assert floatStamp.getBits() == 32; return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN()); @@ -959,6 +1044,9 @@ public class FloatStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return StampFactory.empty(JavaKind.Float); + } FloatStamp floatStamp = (FloatStamp) stamp; assert floatStamp.getBits() == 64; return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index 2ca05ce0a77..28054cb3e5a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -122,11 +122,11 @@ public final class IntegerStamp extends PrimitiveStamp { return new IntegerStamp(bits, lowerBoundTmp, upperBoundTmp, defaultMask & (downMask | boundedDownMask), defaultMask & upMask & boundedUpMask); } - static long significantBit(long bits, long value) { + private static long significantBit(long bits, long value) { return (value >>> (bits - 1)) & 1; } - static long minValueForMasks(int bits, long downMask, long upMask) { + private static long minValueForMasks(int bits, long downMask, long upMask) { if (significantBit(bits, upMask) == 0) { // Value is always positive. Minimum value always positive. assert significantBit(bits, downMask) == 0; @@ -137,7 +137,7 @@ public final class IntegerStamp extends PrimitiveStamp { } } - static long maxValueForMasks(int bits, long downMask, long upMask) { + private static long maxValueForMasks(int bits, long downMask, long upMask) { if (significantBit(bits, downMask) == 1) { // Value is always negative. Maximum value always negative. assert significantBit(bits, upMask) == 1; @@ -330,6 +330,12 @@ public final class IntegerStamp extends PrimitiveStamp { if (otherStamp == this) { return this; } + if (isEmpty()) { + return otherStamp; + } + if (otherStamp.isEmpty()) { + return this; + } IntegerStamp other = (IntegerStamp) otherStamp; return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask); } @@ -413,7 +419,7 @@ public final class IntegerStamp extends PrimitiveStamp { return super.equals(other); } - public static long upMaskFor(int bits, long lowerBound, long upperBound) { + private static long upMaskFor(int bits, long lowerBound, long upperBound) { long mask = lowerBound | upperBound; if (mask == 0) { return 0; @@ -595,6 +601,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp s) { + if (s.isEmpty()) { + return s; + } IntegerStamp stamp = (IntegerStamp) s; int bits = stamp.getBits(); if (stamp.lowerBound == stamp.upperBound) { @@ -622,6 +631,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; @@ -715,6 +730,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; @@ -885,6 +906,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; JavaKind javaKind = a.getStackKind(); @@ -952,6 +979,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; JavaKind javaKind = a.getStackKind(); @@ -1046,6 +1079,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; assert a.getBits() == b.getBits(); @@ -1083,6 +1122,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; assert a.getBits() == b.getBits(); @@ -1121,6 +1166,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp) { + if (stamp.isEmpty()) { + return stamp; + } IntegerStamp integerStamp = (IntegerStamp) stamp; int bits = integerStamp.getBits(); long defaultMask = CodeUtil.mask(bits); @@ -1140,6 +1188,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; assert a.getBits() == b.getBits(); @@ -1167,6 +1221,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; assert a.getBits() == b.getBits(); @@ -1192,6 +1252,12 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + if (stamp1.isEmpty()) { + return stamp1; + } + if (stamp2.isEmpty()) { + return stamp2; + } IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp b = (IntegerStamp) stamp2; assert a.getBits() == b.getBits(); @@ -1269,8 +1335,7 @@ public final class IntegerStamp extends PrimitiveStamp { upMask |= value.upMask() << (i & shiftMask); } } - Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask); - return result; + return IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask); } return value.unrestricted(); } @@ -1392,6 +1457,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp input) { + if (input.isEmpty()) { + return input; + } IntegerStamp stamp = (IntegerStamp) input; int bits = stamp.getBits(); if (stamp.lowerBound == stamp.upperBound) { @@ -1419,6 +1487,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { + if (input.isEmpty()) { + return StampFactory.forInteger(resultBits).empty(); + } IntegerStamp stamp = (IntegerStamp) input; assert inputBits == stamp.getBits(); assert inputBits <= resultBits; @@ -1458,6 +1529,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { + if (input.isEmpty()) { + return StampFactory.forInteger(resultBits).empty(); + } IntegerStamp stamp = (IntegerStamp) input; assert inputBits == stamp.getBits(); assert inputBits <= resultBits; @@ -1487,6 +1561,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { + if (input.isEmpty()) { + return StampFactory.forInteger(resultBits).empty(); + } IntegerStamp stamp = (IntegerStamp) input; assert inputBits == stamp.getBits(); assert resultBits <= inputBits; @@ -1526,6 +1603,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp input) { + if (input.isEmpty()) { + return StampFactory.empty(JavaKind.Float); + } IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 32; float lowerBound = stamp.lowerBound(); @@ -1544,6 +1624,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp input) { + if (input.isEmpty()) { + return StampFactory.empty(JavaKind.Float); + } IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 64; float lowerBound = stamp.lowerBound(); @@ -1562,6 +1645,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp input) { + if (input.isEmpty()) { + return StampFactory.empty(JavaKind.Double); + } IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 32; double lowerBound = stamp.lowerBound(); @@ -1580,6 +1666,9 @@ public final class IntegerStamp extends PrimitiveStamp { @Override public Stamp foldStamp(Stamp input) { + if (input.isEmpty()) { + return StampFactory.empty(JavaKind.Double); + } IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 64; double lowerBound = stamp.lowerBound(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java index d726673a6cd..e73e1f259dc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java @@ -161,6 +161,10 @@ public class StampFactory { return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits)); } + public static IntegerStamp forUnsignedInteger(int bits) { + return forUnsignedInteger(bits, 0, NumUtil.maxValueUnsigned(bits), 0, CodeUtil.mask(bits)); + } + public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) { return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsignedLong.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsignedLong.java new file mode 100644 index 00000000000..c3531df832f --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsignedLong.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018, 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. + * + * 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.core.common.util; + +public final class UnsignedLong { + private final long value; + + public UnsignedLong(long value) { + this.value = value; + } + + public long asLong() { + return value; + } + + public boolean equals(long unsignedValue) { + return value == unsignedValue; + } + + public boolean isLessThan(long unsignedValue) { + return Long.compareUnsigned(value, unsignedValue) < 0; + } + + public boolean isLessOrEqualTo(long unsignedValue) { + return Long.compareUnsigned(value, unsignedValue) <= 0; + } + + public UnsignedLong times(long unsignedValue) { + if (unsignedValue != 0 && Long.compareUnsigned(value, Long.divideUnsigned(0xffff_ffff_ffff_ffffL, unsignedValue)) > 0) { + throw new ArithmeticException(); + } + return new UnsignedLong(value * unsignedValue); + } + + public UnsignedLong minus(long unsignedValue) { + if (Long.compareUnsigned(value, unsignedValue) < 0) { + throw new ArithmeticException(); + } + return new UnsignedLong(value - unsignedValue); + } + + public UnsignedLong plus(long unsignedValue) { + if (Long.compareUnsigned(0xffff_ffff_ffff_ffffL - unsignedValue, value) < 0) { + throw new ArithmeticException(); + } + return new UnsignedLong(value + unsignedValue); + } + + public UnsignedLong wrappingPlus(long unsignedValue) { + return new UnsignedLong(value + unsignedValue); + } + + public UnsignedLong wrappingTimes(long unsignedValue) { + return new UnsignedLong(value * unsignedValue); + } + + @Override + public String toString() { + return "UnsignedLong(" + Long.toUnsignedString(value) + ")"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UnsignedLong that = (UnsignedLong) o; + return value == that.value; + } + + @Override + public int hashCode() { + return Long.hashCode(value); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BasePhaseBinaryGraphTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BasePhaseBinaryGraphTest.java new file mode 100644 index 00000000000..0d4a3b1518a --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BasePhaseBinaryGraphTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011, 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. + * + * 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.core.test; + +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.printer.BinaryGraphPrinter; +import static org.junit.Assert.assertEquals; +import org.junit.Before; +import org.junit.Test; + +public class BasePhaseBinaryGraphTest { + private MyPhase phase; + private BinaryGraphPrinter printer; + + @Before + public void createPhase() { + phase = new MyPhase(); + } + + @Before + public void createPrinter() throws Exception { + printer = new BinaryGraphPrinter(DebugContext.DISABLED, null); + } + + @Test + public void phaseNameIsRecognizedAsType() { + String res = printer.typeName(phase.getName()); + assertEquals(MyPhase.class.getName(), res); + } + + private static final class MyPhase extends BasePhase { + @Override + protected void run(StructuredGraph graph, Void context) { + } + + @Override + protected CharSequence getName() { + return super.getName(); + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java new file mode 100644 index 00000000000..9d7259a9089 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 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. + * + * 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.core.test; + +import org.junit.Test; + +public class ConditionalNodeTest extends GraalCompilerTest { + + @SuppressWarnings("unused") private static int sink0; + @SuppressWarnings("unused") private static int sink1; + + @Test + public void test0() { + test("conditionalTest0", 0); + test("conditionalTest0", 1); + } + + public static int conditionalTest0(int a) { + int value; + if (a == 1) { + value = -1; + sink1 = 0; + } else { + value = 6; + sink1 = 1; + } + sink0 = 1; + return Math.max(value, 6); + } + + @Test + public void test1() { + test("conditionalTest1", 0); + test("conditionalTest1", 1); + } + + public static int conditionalTest1(int a) { + int value; + if (a == 1) { + value = -1; + sink1 = 0; + } else { + value = 6; + sink1 = 1; + } + sink0 = 1; + return Math.max(6, value); + } + + @Test + public void test2() { + test("conditionalTest2", 0); + test("conditionalTest2", 1); + } + + public static int conditionalTest2(int a) { + int value; + if (a == 1) { + value = -1; + sink1 = 0; + } else { + value = 6; + sink1 = 1; + } + sink0 = 1; + return Math.min(value, -1); + } + + @Test + public void test3() { + test("conditionalTest3", 0); + test("conditionalTest3", 1); + } + + public static int conditionalTest3(int a) { + int value; + if (a == 1) { + value = -1; + sink1 = 0; + } else { + value = 6; + sink1 = 1; + } + sink0 = 1; + return Math.min(-1, value); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java index 1bd89c5f6d9..61cacfde4a8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java @@ -30,6 +30,7 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.loop.InductionVariable; import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; @@ -52,25 +53,47 @@ public class CountedLoopTest extends GraalCompilerTest { ValueNode get(InductionVariable iv); } + @FunctionalInterface + private interface StaticIVProperty { + long get(InductionVariable iv); + } + + @FunctionalInterface + private interface IVPredicate { + boolean test(InductionVariable iv); + } + /** * Get a property of an induction variable. - * - * @param property */ - private static int get(IVProperty property, int iv) { + private static int get(@SuppressWarnings("unused") IVProperty property, @SuppressWarnings("unused") StaticIVProperty staticProperty, @SuppressWarnings("unused") IVPredicate constantCheck, + int iv) { + return iv; + } + + private static int get(@SuppressWarnings("unused") IVProperty property, int iv) { + return iv; + } + + private static long get(@SuppressWarnings("unused") IVProperty property, @SuppressWarnings("unused") StaticIVProperty staticProperty, @SuppressWarnings("unused") IVPredicate constantCheck, + long iv) { + return iv; + } + + private static long get(@SuppressWarnings("unused") IVProperty property, long iv) { return iv; } private static class Result { - public int extremum; - public int exitValue; + public long extremum; + public long exitValue; @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + exitValue; - result = prime * result + extremum; + result = prime * result + Long.hashCode(exitValue); + result = prime * result + Long.hashCode(extremum); return result; } @@ -95,7 +118,7 @@ public class CountedLoopTest extends GraalCompilerTest { Result ret = new Result(); for (i = start; i < limit; i += inc) { GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, i); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); } ret.exitValue = get(InductionVariable::exitValueNode, i); return ret; @@ -103,32 +126,42 @@ public class CountedLoopTest extends GraalCompilerTest { @Test public void increment1() { - test("incrementSnippet", 0, 256, 1); + testCounted("incrementSnippet", 0, 256, 1); } @Test public void increment2() { - test("incrementSnippet", 0, 256, 2); + testCounted("incrementSnippet", 0, 256, 2); } @Test public void increment3() { - test("incrementSnippet", 0, 256, 3); + testCounted("incrementSnippet", 0, 256, 3); } @Test public void increment4() { - test("incrementSnippet", -10, Integer.MAX_VALUE, 1); + testCounted("incrementSnippet", -10, 1, Integer.MAX_VALUE); } @Test public void increment5() { - test("incrementSnippet", 256, 256, 1); + testCounted("incrementSnippet", 256, 256, 1); } @Test public void increment6() { - test("incrementSnippet", 257, 256, 1); + testCounted("incrementSnippet", 257, 256, 1); + } + + @Test + public void increment7() { + testCounted("incrementSnippet", -10, Integer.MAX_VALUE, 1); + } + + @Test + public void increment8() { + testCounted("incrementSnippet", -10, Integer.MAX_VALUE - 1, 2); } public static Result incrementEqSnippet(int start, int limit, int step) { @@ -137,7 +170,7 @@ public class CountedLoopTest extends GraalCompilerTest { Result ret = new Result(); for (i = start; i <= limit; i += inc) { GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, i); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); } ret.exitValue = get(InductionVariable::exitValueNode, i); return ret; @@ -145,32 +178,42 @@ public class CountedLoopTest extends GraalCompilerTest { @Test public void incrementEq1() { - test("incrementEqSnippet", 0, 256, 1); + testCounted("incrementEqSnippet", 0, 256, 1); } @Test public void incrementEq2() { - test("incrementEqSnippet", 0, 256, 2); + testCounted("incrementEqSnippet", 0, 256, 2); } @Test public void incrementEq3() { - test("incrementEqSnippet", 0, 256, 3); + testCounted("incrementEqSnippet", 0, 256, 3); } @Test public void incrementEq4() { - test("incrementEqSnippet", -10, 0, Integer.MAX_VALUE); + testCounted("incrementEqSnippet", -10, 0, Integer.MAX_VALUE); } @Test public void incrementEq5() { - test("incrementEqSnippet", 256, 256, 1); + testCounted("incrementEqSnippet", 256, 256, 1); } @Test public void incrementEq6() { - test("incrementEqSnippet", 257, 256, 1); + testCounted("incrementEqSnippet", 257, 256, 1); + } + + @Test + public void incrementEq7() { + testCounted("incrementEqSnippet", -10, Integer.MAX_VALUE - 1, 1); + } + + @Test + public void incrementEq8() { + testCounted("incrementEqSnippet", -10, Integer.MAX_VALUE - 2, 2); } public static Result decrementSnippet(int start, int limit, int step) { @@ -179,7 +222,7 @@ public class CountedLoopTest extends GraalCompilerTest { Result ret = new Result(); for (i = start; i > limit; i -= dec) { GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, i); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); } ret.exitValue = get(InductionVariable::exitValueNode, i); return ret; @@ -187,17 +230,27 @@ public class CountedLoopTest extends GraalCompilerTest { @Test public void decrement1() { - test("decrementSnippet", 256, 0, 1); + testCounted("decrementSnippet", 256, 0, 1); } @Test public void decrement2() { - test("decrementSnippet", 256, 0, 2); + testCounted("decrementSnippet", 256, 0, 2); } @Test public void decrement3() { - test("decrementSnippet", 256, 0, 3); + testCounted("decrementSnippet", 256, 0, 3); + } + + @Test + public void decrement4() { + testCounted("decrementSnippet", Integer.MAX_VALUE, -10, 1); + } + + @Test + public void decrement5() { + testCounted("decrementSnippet", Integer.MAX_VALUE, -10, 2); } public static Result decrementEqSnippet(int start, int limit, int step) { @@ -206,7 +259,7 @@ public class CountedLoopTest extends GraalCompilerTest { Result ret = new Result(); for (i = start; i >= limit; i -= dec) { GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, i); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); } ret.exitValue = get(InductionVariable::exitValueNode, i); return ret; @@ -214,22 +267,32 @@ public class CountedLoopTest extends GraalCompilerTest { @Test public void decrementEq1() { - test("decrementEqSnippet", 256, 0, 1); + testCounted("decrementEqSnippet", 256, 0, 1); } @Test public void decrementEq2() { - test("decrementEqSnippet", 256, 0, 2); + testCounted("decrementEqSnippet", 256, 0, 2); } @Test public void decrementEq3() { - test("decrementEqSnippet", 256, 0, 3); + testCounted("decrementEqSnippet", 256, 0, 3); } @Test public void decrementEq4() { - test("decrementEqSnippet", -10, 0, Integer.MAX_VALUE); + testCounted("decrementEqSnippet", -10, 0, Integer.MAX_VALUE); + } + + @Test + public void decrementEq5() { + testCounted("decrementEqSnippet", Integer.MAX_VALUE, -10, 1); + } + + @Test + public void decrementEq6() { + testCounted("decrementEqSnippet", Integer.MAX_VALUE, -10, 2); } public static Result twoVariablesSnippet() { @@ -238,7 +301,7 @@ public class CountedLoopTest extends GraalCompilerTest { for (int i = 0; i < 1024; i++) { j += 5; GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, j); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, j); } ret.exitValue = get(InductionVariable::exitValueNode, j); return ret; @@ -246,7 +309,83 @@ public class CountedLoopTest extends GraalCompilerTest { @Test public void testTwoVariables() { - test("twoVariablesSnippet"); + testCounted("twoVariablesSnippet"); + } + + public static Result incrementNeqSnippet(int limit) { + int i; + int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive + Result ret = new Result(); + for (i = 0; i != posLimit; i++) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void decrementNeq() { + testCounted("decrementNeqSnippet", 256); + } + + public static Result decrementNeqSnippet(int limit) { + int i; + int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive + Result ret = new Result(); + for (i = posLimit; i != 0; i--) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void incrementNeq() { + testCounted("incrementNeqSnippet", 256); + } + + public static Result incrementLongSnippet(long start, long limit, long step) { + long i; + long inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive + Result ret = new Result(); + for (i = start; i < limit; i += inc) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void incrementLong1() { + testCounted("incrementLongSnippet", 0L, 256L, 1L); + } + + @Test + public void incrementLong2() { + testCounted("incrementLongSnippet", 0L, 256L, 2L); + } + + @Test + public void incrementLong3() { + testCounted("incrementLongSnippet", 0L, 256L, 3L); + } + + @Test + public void incrementLong4() { + testCounted("incrementLongSnippet", -10L, 1L, Long.MAX_VALUE); + } + + @Test + public void incrementLong5() { + testCounted("incrementLongSnippet", 256L, 256L, 1L); + } + + @Test + public void incrementLong6() { + testCounted("incrementLongSnippet", 257L, 256L, 1L); } @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) @@ -255,18 +394,31 @@ public class CountedLoopTest extends GraalCompilerTest { public static final NodeClass TYPE = NodeClass.create(IVPropertyNode.class); private final IVProperty property; + private final StaticIVProperty staticProperty; + private final IVPredicate staticCheck; @Input private ValueNode iv; - protected IVPropertyNode(IVProperty property, ValueNode iv) { + protected IVPropertyNode(IVProperty property, StaticIVProperty staticProperty, IVPredicate staticCheck, ValueNode iv) { super(TYPE, iv.stamp(NodeView.DEFAULT).unrestricted()); this.property = property; + this.staticProperty = staticProperty; + this.staticCheck = staticCheck; this.iv = iv; } public void rewrite(LoopsData loops) { InductionVariable inductionVariable = loops.getInductionVariable(iv); assert inductionVariable != null; - ValueNode node = property.get(inductionVariable); + ValueNode node = null; + if (staticCheck != null) { + assert staticProperty != null; + if (staticCheck.test(inductionVariable)) { + node = ConstantNode.forLong(staticProperty.get(inductionVariable), graph()); + } + } + if (node == null) { + node = property.get(inductionVariable); + } replaceAtUsagesAndDelete(node); } @@ -279,7 +431,13 @@ public class CountedLoopTest extends GraalCompilerTest { @Override protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { Registration r = new Registration(invocationPlugins, CountedLoopTest.class); - r.register2("get", IVProperty.class, int.class, new InvocationPlugin() { + registerPlugins(r, JavaKind.Int); + registerPlugins(r, JavaKind.Long); + super.registerInvocationPlugins(invocationPlugins); + } + + private void registerPlugins(Registration r, JavaKind ivKind) { + r.register2("get", IVProperty.class, ivKind.toJavaClass(), new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) { IVProperty property = null; @@ -287,14 +445,36 @@ public class CountedLoopTest extends GraalCompilerTest { property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant()); } if (property != null) { - b.addPush(JavaKind.Int, new IVPropertyNode(property, arg2)); + b.addPush(ivKind, new IVPropertyNode(property, null, null, arg2)); + return true; + } else { + return false; + } + } + }); + r.register4("get", IVProperty.class, StaticIVProperty.class, IVPredicate.class, ivKind.toJavaClass(), new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { + IVProperty property = null; + StaticIVProperty staticProperty = null; + IVPredicate staticCheck = null; + if (arg1.isConstant()) { + property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant()); + } + if (arg2.isConstant()) { + staticProperty = getSnippetReflection().asObject(StaticIVProperty.class, arg2.asJavaConstant()); + } + if (arg3.isConstant()) { + staticCheck = getSnippetReflection().asObject(IVPredicate.class, arg3.asJavaConstant()); + } + if (property != null && staticProperty != null && staticCheck != null) { + b.addPush(ivKind, new IVPropertyNode(property, staticProperty, staticCheck, arg4)); return true; } else { return false; } } }); - super.registerInvocationPlugins(invocationPlugins); } @Override @@ -308,37 +488,17 @@ public class CountedLoopTest extends GraalCompilerTest { return true; } - public static Result incrementNeqSnippet(int limit) { - int i; - int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive - Result ret = new Result(); - for (i = 0; i != posLimit; i++) { - GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, i); - } - ret.exitValue = get(InductionVariable::exitValueNode, i); - return ret; + private Object[] argsToBind; + + @Override + protected Object[] getArgumentToBind() { + return argsToBind; } - @Test - public void decrementNeq() { - test("decrementNeqSnippet", 256); - } - - public static Result decrementNeqSnippet(int limit) { - int i; - int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive - Result ret = new Result(); - for (i = posLimit; i != 0; i--) { - GraalDirectives.controlFlowAnchor(); - ret.extremum = get(InductionVariable::extremumNode, i); - } - ret.exitValue = get(InductionVariable::exitValueNode, i); - return ret; - } - - @Test - public void incrementNeq() { - test("incrementNeqSnippet", 256); + public void testCounted(String snippetName, Object... args) { + test(snippetName, args); + argsToBind = args; + test(snippetName, args); + argsToBind = null; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java index 04972d5c321..991fab6af30 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.core.test; +import static java.lang.reflect.Modifier.isStatic; import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; @@ -47,6 +48,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Supplier; +import jdk.vm.ci.meta.JavaConstant; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.test.Graal; @@ -931,7 +933,8 @@ public abstract class GraalCompilerTest extends GraalTest { */ @SuppressWarnings("try") protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) { - if (!forceCompile && graph == null) { + boolean useCache = !forceCompile && getArgumentToBind() == null; + if (useCache && graph == null) { InstalledCode cached = cache.get(installedCodeOwner); if (cached != null) { if (cached.isValid()) { @@ -964,7 +967,7 @@ public abstract class GraalCompilerTest extends GraalTest { throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)")); } } catch (BailoutException e) { - if (retry <= BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) { + if (retry < BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) { // retry (if there is no predefined graph) TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id)); continue; @@ -978,7 +981,7 @@ public abstract class GraalCompilerTest extends GraalTest { throw debug.handle(e); } - if (!forceCompile) { + if (useCache) { cache.put(installedCodeOwner, installedCode); } return installedCode; @@ -1243,12 +1246,33 @@ public abstract class GraalCompilerTest extends GraalTest { DebugContext debug = graph.getDebug(); try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) { graphBuilderSuite.apply(graph, getDefaultHighTierContext()); + Object[] args = getArgumentToBind(); + if (args != null) { + bindArguments(graph, args); + } return graph; } catch (Throwable e) { throw debug.handle(e); } } + protected void bindArguments(StructuredGraph graph, Object[] argsToBind) { + ResolvedJavaMethod m = graph.method(); + Object receiver = isStatic(m.getModifiers()) ? null : this; + Object[] args = argsWithReceiver(receiver, argsToBind); + JavaType[] parameterTypes = m.toParameterTypes(); + assert parameterTypes.length == args.length; + for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { + JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]); + ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph); + param.replaceAtUsages(replacement); + } + } + + protected Object[] getArgumentToBind() { + return null; + } + protected PhaseSuite getEagerGraphBuilderSuite() { return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java index 7f319c38a80..46a4502ea97 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java @@ -77,8 +77,7 @@ public class GraphEncoderTest extends GraalCompilerTest { } for (StructuredGraph originalGraph : originalGraphs) { - EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph.getAssumptions(), - originalGraph.getMethods()); + EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph); GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java new file mode 100644 index 00000000000..dbb60193403 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018, 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. + * + * 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.core.test; + +import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount; +import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isEmpty; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Test; + +import jdk.vm.ci.meta.JavaKind; + +public class SwitchDyingLoopTest extends GraalCompilerTest { + + @SuppressWarnings("fallthrough") + public static int snippet(int a, int n) { + int r = 0; + loop: for (int i = 0; i < n; i++) { + int v = (i * 167 + 13) & 0xff; + switch (v & a) { + case 0x80: + r += 1; // fall through + case 0x40: + r += 2; // fall through + case 0x20: + r += 3; + continue; + case 0x08: + r += 5; // fall through + case 0x04: + r += 7; // fall through + case 0x02: + r += 9; // fall through + default: + break loop; + } + } + return r; + } + + @Test + public void test() { + CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(); + HighTierContext highTierContext = getDefaultHighTierContext(); + StructuredGraph graph = parseEager("snippet", StructuredGraph.AllowAssumptions.YES); + // there should be 1 loop and 1 switch + assertThat(graph.getNodes(LoopBeginNode.TYPE), hasCount(1)); + assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1)); + canonicalizerPhase.apply(graph, highTierContext); + // after canonicalization, the loop and switch should still be there + assertThat(graph.getNodes(LoopBeginNode.TYPE), hasCount(1)); + assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1)); + // add stamp to `a` so that paths leading to continue can be trimmed + ParameterNode parameter = graph.getParameter(0); + assertNotNull(parameter); + parameter.setStamp(StampFactory.forInteger(JavaKind.Int, 0, 255, 0, 0xf)); + canonicalizerPhase.apply(graph, highTierContext); + // the loop should have disappeared and there should still be a switch + assertThat(graph.getNodes(LoopBeginNode.TYPE), isEmpty()); + assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1)); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java index efe909d5db2..fc20da2d145 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java @@ -74,9 +74,9 @@ public class TrivialInliningExplosionTest extends GraalCompilerTest { int afterCompileSize = lastCompiledGraph.getNodeCount(); // The values of afterParseSize and afterCompileSize when this - // test was written were 849 and 848 respectively. - Assert.assertTrue(afterParseSize < 2000); - Assert.assertTrue(afterCompileSize < 2000); + // test was written were 3223 and 3505 respectively. + Assert.assertTrue(afterParseSize < 4000); + Assert.assertTrue(afterCompileSize < 4000); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsignedLongTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsignedLongTest.java new file mode 100644 index 00000000000..b8b00417bdb --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsignedLongTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 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. + * + * 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.core.test; + +import org.graalvm.compiler.core.common.util.UnsignedLong; +import org.junit.Assert; +import org.junit.Test; + +public class UnsignedLongTest { + @Test + public void testEquals() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertTrue(fortyTwo.equals(42)); + Assert.assertFalse(fortyTwo.equals(99)); + UnsignedLong longFortyTwo = new UnsignedLong(0x42_0000_8888L); + Assert.assertTrue(longFortyTwo.equals(0x42_0000_8888L)); + Assert.assertFalse(longFortyTwo.equals(0x99_0000_8888L)); + UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L); + Assert.assertTrue(longUnsigned.equals(0x8000_7777_0000_8888L)); + Assert.assertFalse(longUnsigned.equals(0xf000_7777_0000_8888L)); + } + + @Test + public void testIsLessThan() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertTrue(fortyTwo.isLessThan(45)); + Assert.assertFalse(fortyTwo.isLessThan(42)); + Assert.assertFalse(fortyTwo.isLessThan(40)); + Assert.assertTrue(fortyTwo.isLessThan(0xffff_ffff_ffff_ffffL)); + UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L); + Assert.assertTrue(longUnsigned.isLessThan(0xffff_ffff_ffff_ffffL)); + Assert.assertFalse(longUnsigned.isLessThan(42)); + Assert.assertFalse(longUnsigned.isLessThan(0x8000_0777_0000_8888L)); + Assert.assertFalse(longUnsigned.isLessThan(0x8000_7777_0000_8888L)); + } + + @Test + public void testIsLessOrEqualTo() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertTrue(fortyTwo.isLessOrEqualTo(45)); + Assert.assertTrue(fortyTwo.isLessOrEqualTo(42)); + Assert.assertFalse(fortyTwo.isLessOrEqualTo(40)); + Assert.assertTrue(fortyTwo.isLessOrEqualTo(0xffff_ffff_ffff_ffffL)); + UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L); + Assert.assertTrue(longUnsigned.isLessOrEqualTo(0xffff_ffff_ffff_ffffL)); + Assert.assertFalse(longUnsigned.isLessOrEqualTo(42)); + Assert.assertFalse(longUnsigned.isLessOrEqualTo(0x8000_0777_0000_8888L)); + Assert.assertTrue(longUnsigned.isLessOrEqualTo(0x8000_7777_0000_8888L)); + } + + @Test + public void testTimes() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertEquals(42 * 42, fortyTwo.times(42).asLong()); + Assert.assertEquals(0xffff_ffff_ffff_fff0L, fortyTwo.times(0x618618618618618L).asLong()); + } + + @Test(expected = ArithmeticException.class) + public void testTimesException() { + UnsignedLong fortyTwo = new UnsignedLong(42); + fortyTwo.times(0x618618618618619L); + } + + @Test + public void testMinus() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertEquals(0, fortyTwo.minus(42).asLong()); + Assert.assertEquals(40, fortyTwo.minus(2).asLong()); + UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L); + Assert.assertEquals(0, longUnsigned.minus(0xffff_ffff_ffff_fff0L).asLong()); + } + + @Test(expected = ArithmeticException.class) + public void testMinusException() { + UnsignedLong fortyTwo = new UnsignedLong(42); + fortyTwo.minus(43); + } + + @Test(expected = ArithmeticException.class) + public void testMinusException2() { + UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L); + longUnsigned.minus(0xffff_ffff_ffff_fff1L); + } + + @Test + public void testPlus() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertEquals(84, fortyTwo.plus(42).asLong()); + Assert.assertEquals(44, fortyTwo.plus(2).asLong()); + UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L); + Assert.assertEquals(0xffff_ffff_ffff_ffffL, longUnsigned.plus(0xf).asLong()); + } + + @Test(expected = ArithmeticException.class) + public void testPlusException() { + UnsignedLong fortyTwo = new UnsignedLong(42); + fortyTwo.plus(0xffff_ffff_ffff_fff0L); + } + + @Test(expected = ArithmeticException.class) + public void testPlusException2() { + UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L); + longUnsigned.plus(42); + } + + @Test + public void testWrappingTimes() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertEquals(0x1a, fortyTwo.wrappingTimes(0x618618618618619L).asLong()); + } + + @Test + public void testWrappingPlus() { + UnsignedLong fortyTwo = new UnsignedLong(42); + Assert.assertEquals(0x1a, fortyTwo.wrappingPlus(0xffff_ffff_ffff_fff0L).asLong()); + UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L); + Assert.assertEquals(0x1a, longUnsigned.wrappingPlus(42).asLong()); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java index c005152cbc7..093e0ab38e2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java @@ -240,6 +240,7 @@ public class GraalCompiler { debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier"); debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); + graph.logInliningTree(); } catch (Throwable e) { throw debug.handle(e); } finally { 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 a781a4251d3..7091847e552 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 @@ -316,6 +316,10 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio return values.toArray(new Value[values.size()]); } + public void doBlockPrologue(@SuppressWarnings("unused") Block block, @SuppressWarnings("unused") OptionValues options) { + + } + @Override @SuppressWarnings("try") public void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap) { @@ -341,6 +345,7 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio } } } + doBlockPrologue(block, options); List nodes = blockMap.get(block); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java index 358d6cb0b4f..ac4a0c6c9c7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -45,6 +45,7 @@ import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.NodeCounterPhase; import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase; @@ -74,6 +75,10 @@ public class HighTier extends PhaseSuite { appendPhase(canonicalizer); + if (NodeCounterPhase.Options.NodeCounters.getValue(options)) { + appendPhase(new NodeCounterPhase()); + } + if (Options.Inline.getValue(options)) { appendPhase(new InliningPhase(canonicalizer)); appendPhase(new DeadCodeEliminationPhase(Optional)); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java index a27f5a2048a..9c4921683e6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java @@ -178,7 +178,7 @@ public abstract class Backend implements TargetProvider, ValueKindFactory - + diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java index 9f0a763c312..1151396955b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java @@ -22,6 +22,9 @@ */ package org.graalvm.compiler.graph; +import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Default; +import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Track; +import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.UpdateOnly; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; @@ -33,6 +36,7 @@ import java.util.function.Consumer; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; import org.graalvm.collections.UnmodifiableEconomicMap; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; @@ -65,6 +69,13 @@ public class Graph { DeepFreeze } + public enum SourcePositionTracking { + Default, + Ignore, + UpdateOnly, + Track + } + public final String name; /** @@ -80,7 +91,7 @@ public class Graph { /** * Records if updating of node source information is required when performing inlining. */ - boolean seenNodeSourcePosition; + protected SourcePositionTracking trackNodeSourcePosition; /** * The number of valid entries in {@link #nodes}. @@ -195,7 +206,7 @@ public class Graph { * was opened */ public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) { - return sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null; + return trackNodeSourcePosition() && sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null; } /** @@ -212,16 +223,26 @@ public class Graph { * to short circuit logic for updating those positions after inlining since that requires * visiting every node in the graph. */ - public boolean mayHaveNodeSourcePosition() { - assert seenNodeSourcePosition || verifyHasNoSourcePosition(); - return seenNodeSourcePosition; + public boolean updateNodeSourcePosition() { + return trackNodeSourcePosition == Track || trackNodeSourcePosition == UpdateOnly; } - private boolean verifyHasNoSourcePosition() { - for (Node node : getNodes()) { - assert node.getNodeSourcePosition() == null; + public boolean trackNodeSourcePosition() { + return trackNodeSourcePosition == Track; + } + + public void setTrackNodeSourcePosition() { + if (trackNodeSourcePosition != Track) { + assert trackNodeSourcePosition == Default : trackNodeSourcePosition; + trackNodeSourcePosition = Track; } - return true; + } + + public static SourcePositionTracking trackNodeSourcePositionDefault(OptionValues options, DebugContext debug) { + if (GraalOptions.TrackNodeSourcePosition.getValue(options) || debug.isDumpEnabledForMethod()) { + return Track; + } + return Default; } /** @@ -255,6 +276,7 @@ public class Graph { iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds()); this.name = name; this.options = options; + this.trackNodeSourcePosition = trackNodeSourcePositionDefault(options, debug); assert debug != null; this.debug = debug; @@ -358,6 +380,9 @@ public class Graph { */ protected Graph copy(String newName, Consumer> duplicationMapCallback, DebugContext debugForCopy) { Graph copy = new Graph(newName, options, debugForCopy); + if (trackNodeSourcePosition()) { + copy.setTrackNodeSourcePosition(); + } UnmodifiableEconomicMap duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (EconomicMap) null); if (duplicationMapCallback != null) { duplicationMapCallback.accept(duplicates); @@ -1069,10 +1094,9 @@ public class Graph { int id = nodesSize++; nodes[id] = node; node.id = id; - if (currentNodeSourcePosition != null) { + if (currentNodeSourcePosition != null && trackNodeSourcePosition()) { node.setNodeSourcePosition(currentNodeSourcePosition); } - seenNodeSourcePosition = seenNodeSourcePosition || node.getNodeSourcePosition() != null; updateNodeCaches(node); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InlineCacheGuardPosition.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InlineCacheGuardPosition.java new file mode 100644 index 00000000000..f7ea84c3652 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InlineCacheGuardPosition.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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. + * + * 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.graph; + +import java.util.Objects; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class InlineCacheGuardPosition extends NodeSourcePosition { + private final ResolvedJavaType dispatchedType; + private final ResolvedJavaMethod concreteMethod; + private final int hashCode; + + public InlineCacheGuardPosition(NodeSourcePosition callStack, ResolvedJavaType dispatchedType, ResolvedJavaMethod targetMethod) { + super(callStack.getCaller(), callStack.getMethod(), callStack.getBCI()); + this.concreteMethod = targetMethod; + this.dispatchedType = dispatchedType; + this.hashCode = super.hashCode() + 7 * ((dispatchedType == null) ? 0 : dispatchedType.hashCode()) + 31 * targetMethod.hashCode(); + } + + public ResolvedJavaType getDispatchedType() { + return dispatchedType; + } + + public ResolvedJavaMethod getTargetMethod() { + return concreteMethod; + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && getClass() == obj.getClass()) { + InlineCacheGuardPosition that = (InlineCacheGuardPosition) obj; + if (hashCode != that.hashCode) { + return false; + } + if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) && + Objects.equals(this.concreteMethod, that.concreteMethod) && Objects.equals(this.dispatchedType, that.dispatchedType)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "dispatchedType=" + (dispatchedType == null ? "null" : dispatchedType.getName()) + " target_method=" + concreteMethod.getName() + " target_method_class=" + + concreteMethod.getDeclaringClass().getName() + " position=" + super.toString(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java index 0f0c41299af..2dd4131de83 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java @@ -593,10 +593,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { * Set the source position to {@code sourcePosition}. */ public void setNodeSourcePosition(NodeSourcePosition sourcePosition) { + assert sourcePosition != null || this.sourcePosition == null || this.sourcePosition.isPlaceholder() : "Invalid source position at node with id " + id; this.sourcePosition = sourcePosition; - if (sourcePosition != null && graph != null && !graph.seenNodeSourcePosition) { - graph.seenNodeSourcePosition = true; - } + // assert sourcePosition == null || graph == null || graph.trackNodeSourcePosition; } /** @@ -920,6 +919,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { } newNode.graph = into; newNode.id = INITIAL_ID; + if (sourcePosition != null && (into == null || into.updateNodeSourcePosition())) { + newNode.setNodeSourcePosition(sourcePosition); + } if (into != null) { into.register(newNode); } @@ -928,9 +930,6 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { if (into != null && useIntoLeafNodeCache) { into.putNodeIntoCache(newNode); } - if (graph != null && into != null && sourcePosition != null) { - newNode.setNodeSourcePosition(sourcePosition); - } newNode.afterClone(this); return newNode; } @@ -1195,6 +1194,15 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { return getNodeClass().dataEquals(this, other); } + /** + * Determines if this node is equal to the other node while ignoring differences in + * {@linkplain Successor control-flow} edges. + * + */ + public boolean dataFlowEquals(Node other) { + return this == other || nodeClass == other.getNodeClass() && this.valueEquals(other) && nodeClass.equalInputs(this, other); + } + public final void pushInputs(NodeStack stack) { getNodeClass().pushInputs(this, stack); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java index 7af23d60a85..516b3bf810a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java @@ -104,7 +104,7 @@ public final class NodeClass extends FieldIntrospection { * Gets the {@link NodeClass} associated with a given {@link Class}. */ public static NodeClass create(Class c) { - assert get(c) == null; + assert getUnchecked(c) == null; Class superclass = c.getSuperclass(); NodeClass nodeSuperclass = null; if (superclass != NODE_CLASS) { @@ -114,9 +114,9 @@ public final class NodeClass extends FieldIntrospection { } @SuppressWarnings("unchecked") - public static NodeClass get(Class superclass) { + private static NodeClass getUnchecked(Class clazz) { try { - Field field = superclass.getDeclaredField("TYPE"); + Field field = clazz.getDeclaredField("TYPE"); field.setAccessible(true); return (NodeClass) field.get(null); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { @@ -124,6 +124,14 @@ public final class NodeClass extends FieldIntrospection { } } + public static NodeClass get(Class clazz) { + NodeClass result = getUnchecked(clazz); + if (result == null && clazz != NODE_CLASS) { + throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName()); + } + return result; + } + private static final Class NODE_CLASS = Node.class; private static final Class INPUT_LIST_CLASS = NodeInputList.class; private static final Class SUCCESSOR_LIST_CLASS = NodeSuccessorList.class; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java index 688eb793968..660dc2c7464 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java @@ -22,31 +22,100 @@ */ package org.graalvm.compiler.graph; +import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.None; +import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Placeholder; +import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Substitution; + import java.util.Objects; +import org.graalvm.compiler.bytecode.BytecodeDisassembler; +import org.graalvm.compiler.bytecode.Bytecodes; + +import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; public class NodeSourcePosition extends BytecodePosition { - /** - * The receiver of the method this frame refers to. - */ - private final JavaConstant receiver; - private final int hashCode; + private static final boolean STRICT_SOURCE_POSITION = Boolean.getBoolean("debug.graal.SourcePositionStrictChecks"); + private static final boolean SOURCE_POSITION_BYTECODES = Boolean.getBoolean("debug.graal.SourcePositionDisassemble"); - public NodeSourcePosition(JavaConstant receiver, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { + private final int hashCode; + private final Marker marker; + private final SourceLanguagePosition sourceLanguagePosition; + + /** + * Remove marker frames. + */ + public NodeSourcePosition trim() { + if (marker != None) { + return null; + } + NodeSourcePosition caller = getCaller(); + if (caller != null) { + caller = caller.trim(); + } + if (caller != getCaller()) { + return new NodeSourcePosition(caller, getMethod(), getBCI()); + } + return this; + } + + enum Marker { + None, + Placeholder, + Substitution + } + + public NodeSourcePosition(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { + this(caller, method, bci, None); + } + + public NodeSourcePosition(NodeSourcePosition caller, ResolvedJavaMethod method, int bci, Marker marker) { + this(null, caller, method, bci, marker); + + } + + public NodeSourcePosition(SourceLanguagePosition sourceLanguagePosition, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { + this(sourceLanguagePosition, caller, method, bci, None); + } + + public NodeSourcePosition(SourceLanguagePosition sourceLanguagePosition, NodeSourcePosition caller, ResolvedJavaMethod method, int bci, Marker marker) { super(caller, method, bci); if (caller == null) { this.hashCode = 31 * bci + method.hashCode(); } else { this.hashCode = caller.hashCode * 7 + 31 * bci + method.hashCode(); } - this.receiver = receiver; - assert receiver == null || method.getDeclaringClass().isInstance(receiver); + this.marker = marker; + this.sourceLanguagePosition = sourceLanguagePosition; + } + + public static NodeSourcePosition placeholder(ResolvedJavaMethod method) { + return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Placeholder); + } + + public static NodeSourcePosition placeholder(ResolvedJavaMethod method, int bci) { + return new NodeSourcePosition(null, method, bci, Placeholder); + } + + public boolean isPlaceholder() { + return marker == Placeholder; + } + + public static NodeSourcePosition substitution(ResolvedJavaMethod method) { + return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Substitution); + } + + public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { + return new NodeSourcePosition(caller, method, bci, Substitution); + } + + public boolean isSubstitution() { + return marker == Substitution; } @Override @@ -60,7 +129,7 @@ public class NodeSourcePosition extends BytecodePosition { return false; } if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) && - Objects.equals(this.receiver, that.receiver)) { + Objects.equals(this.sourceLanguagePosition, that.sourceLanguagePosition)) { return true; } } @@ -72,8 +141,18 @@ public class NodeSourcePosition extends BytecodePosition { return hashCode; } - public JavaConstant getReceiver() { - return receiver; + public int depth() { + int d = 0; + NodeSourcePosition pos = this; + while (pos != null) { + d++; + pos = pos.getCaller(); + } + return d; + } + + public SourceLanguagePosition getSourceLanauage() { + return sourceLanguagePosition; } @Override @@ -81,17 +160,29 @@ public class NodeSourcePosition extends BytecodePosition { return (NodeSourcePosition) super.getCaller(); } - public NodeSourcePosition addCaller(JavaConstant newCallerReceiver, NodeSourcePosition link) { - if (getCaller() == null) { - assert newCallerReceiver == null || receiver == null : "replacing receiver"; - return new NodeSourcePosition(newCallerReceiver, link, getMethod(), getBCI()); - } else { - return new NodeSourcePosition(receiver, getCaller().addCaller(newCallerReceiver, link), getMethod(), getBCI()); - } + public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link) { + return addCaller(newSourceLanguagePosition, link, false); } public NodeSourcePosition addCaller(NodeSourcePosition link) { - return addCaller(null, link); + return addCaller(null, link, false); + } + + public NodeSourcePosition addCaller(NodeSourcePosition link, boolean isSubstitution) { + return addCaller(null, link, isSubstitution); + } + + public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link, boolean isSubstitution) { + if (getCaller() == null) { + if (isPlaceholder()) { + return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), 0); + } + assert link == null || isSubstitution || verifyCaller(this, link) : link; + + return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), getBCI()); + } else { + return new NodeSourcePosition(getCaller().addCaller(newSourceLanguagePosition, link, isSubstitution), getMethod(), getBCI()); + } } @Override @@ -99,9 +190,9 @@ public class NodeSourcePosition extends BytecodePosition { StringBuilder sb = new StringBuilder(100); NodeSourcePosition pos = this; while (pos != null) { - MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); - if (pos.receiver != null) { - sb.append("receiver=" + pos.receiver + " "); + format(sb, pos); + if (pos.sourceLanguagePosition != null) { + sb.append(" source=" + pos.sourceLanguagePosition.toShortString()); } pos = pos.getCaller(); if (pos != null) { @@ -110,4 +201,55 @@ public class NodeSourcePosition extends BytecodePosition { } return sb.toString(); } + + private static void format(StringBuilder sb, NodeSourcePosition pos) { + MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); + if (SOURCE_POSITION_BYTECODES) { + String disassembly = BytecodeDisassembler.disassembleOne(pos.getMethod(), pos.getBCI()); + if (disassembly != null && disassembly.length() > 0) { + sb.append(" // "); + sb.append(disassembly); + } + } + } + + String shallowToString() { + StringBuilder sb = new StringBuilder(100); + format(sb, this); + return sb.toString(); + } + + public boolean verify() { + NodeSourcePosition current = this; + NodeSourcePosition caller = getCaller(); + while (caller != null) { + assert verifyCaller(current, caller) : current; + current = caller; + caller = caller.getCaller(); + } + return true; + } + + private static boolean verifyCaller(NodeSourcePosition current, NodeSourcePosition caller) { + if (!STRICT_SOURCE_POSITION) { + return true; + } + if (BytecodeFrame.isPlaceholderBci(caller.getBCI())) { + return true; + } + int opcode = BytecodeDisassembler.getBytecodeAt(caller.getMethod(), caller.getBCI()); + JavaMethod method = BytecodeDisassembler.getInvokedMethodAt(caller.getMethod(), caller.getBCI()); + /* + * It's not really possible to match the declaring classes since this might be an interface + * invoke. Matching name and signature probably provides enough accuracy. + */ + assert method == null || (method.getName().equals(current.getMethod().getName()) && + method.getSignature().equals(current.getMethod().getSignature())) || + caller.getMethod().getName().equals("linkToTargetMethod") || + opcode == Bytecodes.INVOKEDYNAMIC || + caller.getMethod().getDeclaringClass().getName().startsWith("Ljava/lang/invoke/LambdaForm$") || + current.getMethod().getName().equals("callInlined") : "expected " + method + " but found " + + current.getMethod(); + return true; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java new file mode 100644 index 00000000000..cf7f6bb94e8 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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. + * + * 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.graph; + +import java.util.Map; + +/** + * Provides a path to report information about a high level language source position to the Graph + * Visualizer. + */ +public interface SourceLanguagePosition { + + /** + * This is called during dumping of Nodes. The implementation should add any properties which + * describe this source position. The actual keys and values used are a private contract between + * the language implementation and the Graph Visualizer. + */ + void addSourceInformation(Map props); + + /** + * Produce a compact description of this position suitable for printing. + */ + String toShortString(); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePositionProvider.java similarity index 77% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePositionProvider.java index cbd0e24ee35..21bd9a2c276 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePositionProvider.java @@ -20,20 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.compiler.core.common; +package org.graalvm.compiler.graph; -public enum TraceInliningMode { - None(false), - Linear(true), - Tree(true); +import jdk.vm.ci.meta.JavaConstant; - private final boolean tracing; - - TraceInliningMode(boolean tracing) { - this.tracing = tracing; - } - - public boolean isTracing() { - return tracing; - } +/** + * Provider of {@link SourceLanguagePosition} for a constant if it represents an AST node. + */ +public interface SourceLanguagePositionProvider { + SourceLanguagePosition getPosition(JavaConstant node); } 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 a6bfcb92e49..28f3c6db2e8 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 @@ -288,33 +288,37 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend { } private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) { - /* - * Insert a nop at the start of the prolog so we can patch in a branch if we need to - * invalidate the method later. - */ + emitInvalidatePlaceholder(crb, masm); + crb.emit(lir); + } + + /** + * Insert a nop at the start of the prolog so we can patch in a branch if we need to invalidate + * the method later. + * + * @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html" + */ + public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) { crb.blockComment("[nop for method invalidation]"); masm.nop(); - - crb.emit(lir); } private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) { HotSpotProviders providers = getProviders(); HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; if (!frameContext.isStub) { + HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); - HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER); Register helper = AArch64Call.isNearCall(linkage) ? null : scratch; AArch64Call.directCall(crb, masm, linkage, helper, null); - - crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); - linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER); - helper = AArch64Call.isNearCall(linkage) ? null : scratch; - AArch64Call.directCall(crb, masm, linkage, helper, null); } + crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); + ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER); + masm.adr(lr, 0); // Warning: the argument is an offset from the instruction! + AArch64Call.directJmp(crb, masm, linkage); } 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.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 f9d43ce56b2..586ced59150 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 @@ -46,7 +46,9 @@ public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements Blo @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info); + try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) { + AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), 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/AArch64HotSpotMove.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java index b0de7d96da3..8766ddd1fd0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -155,22 +155,24 @@ public class AArch64HotSpotMove { @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - Register ptr = asRegister(input); + Register inputRegister = asRegister(input); Register resultRegister = asRegister(result); - Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr); + Register base = encoding.hasBase() ? asRegister(baseRegister) : null; + emitUncompressCode(masm, inputRegister, resultRegister, base, encoding.getShift(), nonNull); + } + + public static void emitUncompressCode(AArch64MacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) { // result = base + (ptr << shift) - if (nonNull) { - masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift()); - } else if (!encoding.hasBase()) { - masm.add(64, resultRegister, zr, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift()); + if (nonNull || baseReg == null) { + masm.add(64, resReg, baseReg == null ? zr : baseReg, inputRegister, AArch64Assembler.ShiftType.LSL, shift); } else { // if ptr is null it has to be null after decompression Label done = new Label(); - if (!resultRegister.equals(ptr)) { - masm.mov(32, resultRegister, ptr); + if (!resReg.equals(inputRegister)) { + masm.mov(32, resReg, inputRegister); } - masm.cbz(32, resultRegister, done); - masm.add(64, resultRegister, base, resultRegister, AArch64Assembler.ShiftType.LSL, encoding.getShift()); + masm.cbz(32, resReg, done); + masm.add(64, resReg, baseReg, resReg, AArch64Assembler.ShiftType.LSL, shift); masm.bind(done); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java index b72925f67eb..0ebadb778ef 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java @@ -65,6 +65,7 @@ import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.Value; +import org.graalvm.compiler.hotspot.HotSpotBackend; public class StubAVXTest extends LIRTest { @@ -72,6 +73,10 @@ public class StubAVXTest extends LIRTest { public void checkAMD64() { Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); Assume.assumeTrue("skipping AVX test", ((AMD64) getTarget().arch).getFeatures().contains(CPUFeature.AVX)); + if (getBackend() instanceof HotSpotBackend) { + HotSpotBackend backend = (HotSpotBackend) getBackend(); + Assume.assumeTrue("skipping because of MaxVectorSize", backend.getRuntime().getVMConfig().maxVectorSize >= 32); + } } private static final DataPointerConstant avxConstant = new ArrayDataPointerConstant(new float[]{1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f}, 32); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java index d2d94c95da2..e14ed05b01c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java @@ -204,7 +204,7 @@ public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering { if (init >= 0 && extremum >= 0) { long shortestTrip = (extremum - init) / stride + 1; - if (shortestTrip == countedLoopInfo.constantMaxTripCount()) { + if (countedLoopInfo.constantMaxTripCount().equals(shortestTrip)) { return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true)); } } 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 a12c5c472b6..552a88e4c7b 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 @@ -25,13 +25,13 @@ package org.graalvm.compiler.hotspot.amd64; import static jdk.vm.ci.amd64.AMD64.rbp; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE; import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; import java.util.ArrayList; import java.util.List; @@ -115,7 +115,7 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp } private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) { - this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes); + this(new AMD64HotSpotLIRKindTool(), new AMD64ArithmeticLIRGenerator(new AMD64HotSpotMaths()), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes); } protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMaths.java similarity index 55% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMaths.java index 3e011324fd1..feff123da43 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMaths.java @@ -31,49 +31,55 @@ import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.Int import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.HotSpotBackend.Options; import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.gen.LIRGenerator; import jdk.vm.ci.meta.Value; -public class AMD64HotSpotArithmeticLIRGenerator extends AMD64ArithmeticLIRGenerator { +/** + * Lowering of selected {@link Math} routines that depends on the value of + * {@link Options#GraalArithmeticStubs}. + */ +public class AMD64HotSpotMaths implements AMD64ArithmeticLIRGenerator.Maths { @Override - public Value emitMathLog(Value input, boolean base10) { - if (GraalArithmeticStubs.getValue(getOptions())) { - return super.emitMathLog(input, base10); + public Variable emitLog(LIRGenerator gen, Value input, boolean base10) { + if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) { + return null; } - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input))); + Variable result = gen.newVariable(LIRKind.combine(input)); + gen.append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, gen.asAllocatable(input))); return result; } @Override - public Value emitMathCos(Value input) { - if (GraalArithmeticStubs.getValue(getOptions())) { - return super.emitMathCos(input); + public Variable emitCos(LIRGenerator gen, Value input) { + if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) { + return null; } - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(COS, result, getLIRGen().asAllocatable(input))); + Variable result = gen.newVariable(LIRKind.combine(input)); + gen.append(new AMD64HotSpotMathIntrinsicOp(COS, result, gen.asAllocatable(input))); return result; } @Override - public Value emitMathSin(Value input) { - if (GraalArithmeticStubs.getValue(getOptions())) { - return super.emitMathSin(input); + public Variable emitSin(LIRGenerator gen, Value input) { + if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) { + return null; } - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(SIN, result, getLIRGen().asAllocatable(input))); + Variable result = gen.newVariable(LIRKind.combine(input)); + gen.append(new AMD64HotSpotMathIntrinsicOp(SIN, result, gen.asAllocatable(input))); return result; } @Override - public Value emitMathTan(Value input) { - if (GraalArithmeticStubs.getValue(getOptions())) { - return super.emitMathTan(input); + public Variable emitTan(LIRGenerator gen, Value input) { + if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) { + return null; } - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(TAN, result, getLIRGen().asAllocatable(input))); + Variable result = gen.newVariable(LIRKind.combine(input)); + gen.append(new AMD64HotSpotMathIntrinsicOp(TAN, result, gen.asAllocatable(input))); return result; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java index 2175bec863c..b57dd58b4f2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java @@ -187,21 +187,26 @@ public class SPARCHotSpotMove { public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { Register inputRegister = asRegister(input); Register resReg = asRegister(result); + Register baseReg = encoding.hasBase() ? asRegister(baseRegister) : null; + emitUncompressCode(masm, inputRegister, resReg, baseReg, encoding.getShift(), nonNull); + } + + public static void emitUncompressCode(SPARCMacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) { Register secondaryInput; - if (encoding.getShift() != 0) { - masm.sll(inputRegister, encoding.getShift(), resReg); + if (shift != 0) { + masm.sll(inputRegister, shift, resReg); secondaryInput = resReg; } else { secondaryInput = inputRegister; } - if (encoding.hasBase()) { + if (baseReg != null) { if (nonNull) { - masm.add(secondaryInput, asRegister(baseRegister), resReg); + masm.add(secondaryInput, baseReg, resReg); } else { Label done = new Label(); BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done); - masm.add(asRegister(baseRegister), secondaryInput, resReg); + masm.add(baseReg, secondaryInput, resReg); masm.bind(done); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java index 4572bd40d45..146296fe83d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -553,6 +553,7 @@ public final class CompileTheWorld { classFileCounter++; if (className.startsWith("jdk.management.") || + className.startsWith("jdk.internal.cmm.*") || // GR-5881: The class initializer for // sun.tools.jconsole.OutputViewer // spawns non-daemon threads for redirecting sysout and syserr. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java new file mode 100644 index 00000000000..d3beddc5a60 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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. + * + * 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 org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class HotSpotLazyInitializationTest extends GraalCompilerTest { + + HotSpotClassInitializationPlugin classInitPlugin = new HotSpotClassInitializationPlugin(); + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + plugins.setClassInitializationPlugin(classInitPlugin); + return plugins; + } + + static boolean initializerRun = false; + + static class X { + static { + initializerRun = true; + } + + static void foo() { + } + } + + public static void invokeStatic() { + X.foo(); + } + + // If constant pool can do eager resolve without eager initialization, then fail if the compiler + // causes the static initializer to run. + private void test(String name) { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool())); + parseEager(method, AllowAssumptions.NO); + Assert.assertFalse(initializerRun); + } + + @Test + public void test1() { + test("invokeStatic"); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java index 0a3a667ff1c..18d6cb873f2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java @@ -24,17 +24,25 @@ package org.graalvm.compiler.hotspot; import static jdk.vm.ci.common.InitTimer.timer; +import java.net.URL; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.phases.LIRPhaseSuite; +import org.graalvm.compiler.options.EnumOptionKey; 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.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.serviceprovider.GraalServices; @@ -48,12 +56,20 @@ import jdk.vm.ci.common.InitTimer; */ public abstract class CompilerConfigurationFactory implements Comparable { + enum ShowConfigurationLevel { + none, + info, + verbose + } + static class Options { // @formatter:off @Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " + "with the highest auto-selection priority is used. To see the set of available configurations, " + "supply the value 'help' to this option.", type = OptionType.Expert) public static final OptionKey CompilerConfiguration = new OptionKey<>(null); + @Option(help = "Writes to the VM log information about the Graal compiler configuration selected.", type = OptionType.User) + public static final OptionKey ShowConfiguration = new EnumOptionKey<>(ShowConfigurationLevel.none); // @formatter:on } @@ -192,6 +208,52 @@ public abstract class CompilerConfigurationFactory implements Comparable List phaseNames(PhaseSuite suite) { + Collection> phases = suite.getPhases(); + List res = new ArrayList<>(phases.size()); + for (BasePhase phase : phases) { + res.add(phase.contractorName()); + } + Collections.sort(res); + return res; + } + + private static List phaseNames(LIRPhaseSuite suite) { + List> phases = suite.getPhases(); + List res = new ArrayList<>(phases.size()); + for (LIRPhase phase : phases) { + res.add(phase.getClass().getName()); + } + Collections.sort(res); + return res; + } } 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 565d92a0a1f..0622f1e7efd 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 @@ -45,8 +45,9 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { */ public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null; + // this uses `1.9` which will give the correct result with `1.9`, `9`, `10` etc. private final boolean isJDK8 = System.getProperty("java.specification.version").compareTo("1.9") < 0; - private final int JDKVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version")); + private final int jdkVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version")); public final String osName = getHostOSName(); public final String osArch = getHostArchitectureName(); public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); @@ -160,6 +161,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class); public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class); public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class); + public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class); public final boolean useTLAB = getFlag("UseTLAB", Boolean.class); public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class); @@ -555,12 +557,10 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int"); - public final byte dirtyCardValue = JDKVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class) : - (JDKVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : - getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int")); - public final byte g1YoungCardValue = JDKVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class) : - (JDKVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) : - getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int")); + public final byte dirtyCardValue = jdkVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class) + : (jdkVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int")); + public final byte g1YoungCardValue = jdkVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class) + : (jdkVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) : getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int")); public final long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*"); public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java index 68904ddfa12..8b358c1f249 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java @@ -91,7 +91,7 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen public static class Options { // @formatter:off @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") - public static final OptionKey GraalArithmeticStubs = new OptionKey<>(true); + public static final OptionKey GraalArithmeticStubs = new OptionKey<>(false); // GR-8276 @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) public static final OptionKey ASMInstructionProfiling = new OptionKey<>(null); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java index 3bba3fbfbcf..825f2822a69 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.hotspot; +import static org.graalvm.util.CollectionsUtil.anyMatch; + import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; @@ -37,9 +39,9 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.code.CompilationResult.CodeComment; import org.graalvm.compiler.code.CompilationResult.JumpTable; -import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.code.DataSection; import org.graalvm.compiler.code.SourceMapping; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeSourcePosition; import jdk.vm.ci.code.CodeCacheProvider; @@ -55,7 +57,6 @@ import jdk.vm.ci.hotspot.HotSpotCompilationRequest; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -210,16 +211,31 @@ public class HotSpotCompiledCodeBuilder { sites.addAll(target.getDataPatches()); sites.addAll(target.getMarks()); - /* - * Translate the source mapping into appropriate info points. In HotSpot only one position - * can really be represented and recording the end PC seems to give the best results and - * corresponds with what C1 and C2 do. - */ if (codeCache.shouldDebugNonSafepoints()) { + /* + * Translate the source mapping into appropriate info points. In HotSpot only one + * position can really be represented and recording the end PC seems to give the best + * results and corresponds with what C1 and C2 do. HotSpot doesn't like to see these + * unless -XX:+DebugNonSafepoints is enabled, so don't emit them in that case. + */ + List sourcePositionSites = new ArrayList<>(); for (SourceMapping source : target.getSourceMappings()) { - sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION)); - assert verifySourcePositionReceivers(source.getSourcePosition()); + NodeSourcePosition sourcePosition = source.getSourcePosition(); + assert sourcePosition.verify(); + sourcePosition = sourcePosition.trim(); + /* + * Don't add BYTECODE_POSITION info points that would potentially create conflicts. + * Under certain conditions the site's pc is not the pc that gets recorded by + * HotSpot (see @code {CodeInstaller::site_Call}). So, avoid adding any source + * positions that can potentially map to the same pc. To do that make sure that the + * source mapping doesn't contain a pc of any important Site. + */ + if (sourcePosition != null && !anyMatch(sites, s -> source.contains(s.pcOffset))) { + sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION)); + + } } + sites.addAll(sourcePositionSites); } SiteComparator c = new SiteComparator(); @@ -245,18 +261,4 @@ public class HotSpotCompiledCodeBuilder { } return sites.toArray(new Site[sites.size()]); } - - /** - * Verifies that the captured receiver type agrees with the declared type of the method. - */ - private static boolean verifySourcePositionReceivers(NodeSourcePosition start) { - NodeSourcePosition pos = start; - while (pos != null) { - if (pos.getReceiver() != null) { - assert ((HotSpotObjectConstant) pos.getReceiver()).asObject(pos.getMethod().getDeclaringClass()) != null; - } - pos = pos.getCaller(); - } - return true; - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java index 7146ad77271..b5c9ff861fc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java @@ -26,8 +26,8 @@ import static jdk.vm.ci.common.InitTimer.timer; import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX; import java.io.PrintStream; -import java.util.Map; import java.util.Collections; +import java.util.Map; import org.graalvm.compiler.debug.MethodFilter; import org.graalvm.compiler.options.Option; @@ -36,6 +36,7 @@ import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.options.OptionsParser; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.serviceprovider.JDK9Method; import jdk.vm.ci.common.InitTimer; import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; @@ -48,6 +49,22 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto private static MethodFilter[] graalCompileOnlyFilter; private static boolean compileGraalWithC1Only; + /** + * Module containing {@link HotSpotJVMCICompilerFactory}. + */ + private Object jvmciModule; + + /** + * Module containing {@link HotSpotGraalCompilerFactory}. + */ + private Object graalModule; + + /** + * Module containing the {@linkplain CompilerConfigurationFactory#selectFactory selected} + * configuration. + */ + private Object compilerConfigurationModule; + private final HotSpotGraalJVMCIServiceLocator locator; HotSpotGraalCompilerFactory(HotSpotGraalJVMCIServiceLocator locator) { @@ -70,6 +87,10 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto assert options == null : "cannot select " + getClass() + " service more than once"; options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; initializeGraalCompilePolicyFields(options); + if (!JDK9Method.Java8OrEarlier) { + jvmciModule = JDK9Method.getModule(HotSpotJVMCICompilerFactory.class); + graalModule = JDK9Method.getModule(HotSpotGraalCompilerFactory.class); + } /* * Exercise this code path early to encourage loading now. This doesn't solve problem of * deadlock during class loading but seems to eliminate it in practice. @@ -102,7 +123,9 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert) public static final OptionKey CompileGraalWithC1Only = new OptionKey<>(true); - @Option(help = "A method filter selecting what should be compiled by Graal. All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert) + @Option(help = "A filter applied to a method the VM has selected for compilation by Graal. " + + "A method not matching the filter is redirected to a lower tier compiler. " + + "The filter format is the same as for the MethodFilter option.", type = OptionType.Expert) public static final OptionKey GraalCompileOnly = new OptionKey<>(null); // @formatter:on @@ -110,7 +133,11 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto @Override public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) { - HotSpotGraalCompiler compiler = createCompiler(runtime, options, CompilerConfigurationFactory.selectFactory(null, options)); + CompilerConfigurationFactory factory = CompilerConfigurationFactory.selectFactory(null, options); + if (!JDK9Method.Java8OrEarlier) { + compilerConfigurationModule = JDK9Method.getModule(factory.getClass()); + } + HotSpotGraalCompiler compiler = createCompiler(runtime, options, factory); // Only the HotSpotGraalRuntime associated with the compiler created via // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving // VM events. @@ -160,15 +187,54 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory"); } + static final ClassLoader JVMCI_LOADER = HotSpotGraalCompilerFactory.class.getClassLoader(); + /* * This method is static so it can be exercised during initialization. */ - private static CompilationLevel adjustCompilationLevelInternal(Class declaringClass, String name, String signature, CompilationLevel level) { + private CompilationLevel adjustCompilationLevelInternal(Class declaringClass, String name, String signature, CompilationLevel level) { if (compileGraalWithC1Only) { if (level.ordinal() > CompilationLevel.Simple.ordinal()) { - String declaringClassName = declaringClass.getName(); - if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) { - return CompilationLevel.Simple; + if (JDK9Method.Java8OrEarlier) { + if (JVMCI_LOADER != null) { + // When running with +UseJVMCIClassLoader all classes in + // the JVMCI loader should be compiled with C1. + try { + if (declaringClass.getClassLoader() == JVMCI_LOADER) { + return CompilationLevel.Simple; + } + } catch (SecurityException e) { + // This is definitely not a JVMCI or Graal class + } + } else { + // JVMCI and Graal are on the bootclasspath so match based on the package. + String declaringClassName = declaringClass.getName(); + if (declaringClassName.startsWith("jdk.vm.ci")) { + return CompilationLevel.Simple; + } + if (declaringClassName.startsWith("org.graalvm.") && + (declaringClassName.startsWith("org.graalvm.compiler.") || + declaringClassName.startsWith("org.graalvm.collections.") || + declaringClassName.startsWith("org.graalvm.compiler.word.") || + declaringClassName.startsWith("org.graalvm.graphio."))) { + return CompilationLevel.Simple; + } + if (declaringClassName.startsWith("com.oracle.graal") && + (declaringClassName.startsWith("com.oracle.graal.enterprise") || + declaringClassName.startsWith("com.oracle.graal.vector") || + declaringClassName.startsWith("com.oracle.graal.asm"))) { + return CompilationLevel.Simple; + } + } + } else { + try { + Object module = JDK9Method.getModule(declaringClass); + if (jvmciModule == module || graalModule == module || compilerConfigurationModule == module) { + return CompilationLevel.Simple; + } + } catch (Throwable e) { + throw new InternalError(e); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java index ad48b0e2956..7ae2198513f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.hotspot; import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; @@ -114,14 +113,9 @@ public class NodeCostDumpUtil { } System.err.printf("Loaded %s node classes...\n", nodeClasses.size()); List> nc = new ArrayList<>(); - for (Class nodeClass : nodeClasses) { - Field f; + for (Class c : nodeClasses) { try { - f = nodeClass.getField("TYPE"); - f.setAccessible(true); - Object val = f.get(null); - NodeClass nodeType = (NodeClass) val; - nc.add(nodeType); + nc.add(NodeClass.get(c)); } catch (Throwable t) { // Silently ignore problems here } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/VerifyMaxRegisterSizePhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/VerifyMaxRegisterSizePhase.java new file mode 100644 index 00000000000..2b249964d1c --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/VerifyMaxRegisterSizePhase.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 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. + * + * 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.lir; + +import java.util.EnumSet; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; + +import jdk.vm.ci.code.TargetDescription; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import jdk.vm.ci.meta.Value; +import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; +import org.graalvm.compiler.lir.LIRInstruction.OperandMode; + +/** + * Checks that no registers exceed the MaxVectorSize flag from the VM config. + */ +public final class VerifyMaxRegisterSizePhase extends PostAllocationOptimizationPhase { + + private final int maxVectorSize; + + public VerifyMaxRegisterSizePhase(int maxVectorSize) { + this.maxVectorSize = maxVectorSize; + } + + @Override + protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) { + LIR lir = lirGenRes.getLIR(); + for (AbstractBlockBase block : lir.getControlFlowGraph().getBlocks()) { + verifyBlock(lir, block); + } + } + + protected void verifyBlock(LIR lir, AbstractBlockBase block) { + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + verifyInstruction(inst); + } + } + + protected void verifyInstruction(LIRInstruction inst) { + inst.visitEachInput(this::verifyOperands); + inst.visitEachOutput(this::verifyOperands); + inst.visitEachAlive(this::verifyOperands); + inst.visitEachTemp(this::verifyOperands); + } + + @SuppressWarnings("unused") + protected void verifyOperands(LIRInstruction instruction, Value value, OperandMode mode, EnumSet flags) { + if (isRegister(value)) { + assert value.getPlatformKind().getSizeInBytes() <= maxVectorSize : "value " + value + " exceeds MaxVectorSize " + maxVectorSize; + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java index f34dba44e97..05a21341e74 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java @@ -25,6 +25,7 @@ package org.graalvm.compiler.hotspot.meta; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; import org.graalvm.compiler.nodes.ConstantNode; @@ -37,6 +38,11 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.ConstantPool; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; public final class HotSpotClassInitializationPlugin implements ClassInitializationPlugin { @Override @@ -73,4 +79,47 @@ public final class HotSpotClassInitializationPlugin implements ClassInitializati result.setStateBefore(frameState); return result; } + + private static final Class hscp; + private static final MethodHandle loadReferencedTypeIIZMH; + + static { + MethodHandle m = null; + Class c = null; + try { + c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class); + m = MethodHandles.lookup().findVirtual(c, "loadReferencedType", MethodType.methodType(void.class, int.class, int.class, boolean.class)); + } catch (Exception e) { + } + loadReferencedTypeIIZMH = m; + hscp = c; + } + + private static boolean isHotSpotConstantPool(ConstantPool cp) { + // jdk.vm.ci.hotspot.HotSpotConstantPool is final, so we can + // directly compare Classes. + return cp.getClass() == hscp; + } + + @Override + public boolean supportsLazyInitialization(ConstantPool cp) { + if (loadReferencedTypeIIZMH != null && isHotSpotConstantPool(cp)) { + return true; + } + return false; + } + + @Override + public void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int opcode) { + if (loadReferencedTypeIIZMH != null && isHotSpotConstantPool(cp)) { + try { + loadReferencedTypeIIZMH.invoke(cp, cpi, opcode, false); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); + } + } else { + cp.loadReferencedType(cpi, opcode); + } + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 94088d33e27..cdf8b8f8e5e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -234,7 +234,7 @@ public class HotSpotGraphBuilderPlugins { b.addPush(JavaKind.Object, object); } else { FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false)); - b.addPush(JavaKind.Object, new DynamicPiNode(object, fixedGuard, javaClass)); + b.addPush(JavaKind.Object, DynamicPiNode.create(b.getAssumptions(), b.getConstantReflection(), object, fixedGuard, javaClass)); } return true; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java index ba8fcde9f16..5d7aaa2bfd3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java @@ -24,6 +24,7 @@ package org.graalvm.compiler.hotspot.meta; import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import java.lang.invoke.MethodHandle; import java.lang.reflect.Type; import java.util.Set; @@ -129,7 +130,7 @@ final class HotSpotInvocationPlugins extends InvocationPlugins { ClassLoader cl = javaClass.getClassLoader(); return cl == null || cl == getClass().getClassLoader() || cl == extLoader; } else { - Object module = JDK9Method.getModule.invoke(javaClass); + Object module = JDK9Method.getModule(javaClass); return trustedModules.contains(module); } } @@ -148,34 +149,43 @@ final class HotSpotInvocationPlugins extends InvocationPlugins { } } + /** + * Gets the set of modules whose methods can be intrinsified. This set is the module owning the + * class of {@code compilerConfiguration} and all its dependencies. + */ private static EconomicSet initTrustedModules(CompilerConfiguration compilerConfiguration) throws GraalError { try { EconomicSet res = EconomicSet.create(); - Object compilerConfigurationModule = JDK9Method.getModule.invoke(compilerConfiguration.getClass()); + Object compilerConfigurationModule = JDK9Method.getModule(compilerConfiguration.getClass()); res.add(compilerConfigurationModule); Class moduleClass = compilerConfigurationModule.getClass(); - Object layer = new JDK9Method(moduleClass, "getLayer").invoke(compilerConfigurationModule); + Object layer = JDK9Method.lookupMethodHandle(moduleClass, "getLayer").invoke(compilerConfigurationModule); Class layerClass = layer.getClass(); - JDK9Method getName = new JDK9Method(moduleClass, "getName"); - Set modules = new JDK9Method(layerClass, "modules").invoke(layer); - Object descriptor = new JDK9Method(moduleClass, "getDescriptor").invoke(compilerConfigurationModule); + MethodHandle getName = JDK9Method.lookupMethodHandle(moduleClass, "getName"); + Set modules = (Set) JDK9Method.lookupMethodHandle(layerClass, "modules").invoke(layer); + Object descriptor = JDK9Method.lookupMethodHandle(moduleClass, "getDescriptor").invoke(compilerConfigurationModule); Class moduleDescriptorClass = descriptor.getClass(); - Set requires = new JDK9Method(moduleDescriptorClass, "requires").invoke(descriptor); - JDK9Method requireNameGetter = null; + Set requires = (Set) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "requires").invoke(descriptor); + boolean isAutomatic = (Boolean) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "isAutomatic").invoke(descriptor); + if (isAutomatic) { + throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module", + getName.invoke(compilerConfigurationModule), compilerConfiguration.getClass().getName())); + } + MethodHandle requireNameGetter = null; for (Object require : requires) { if (requireNameGetter == null) { - requireNameGetter = new JDK9Method(require.getClass(), "name"); + requireNameGetter = JDK9Method.lookupMethodHandle(require.getClass(), "name"); } - String name = requireNameGetter.invoke(require); + String name = (String) requireNameGetter.invoke(require); for (Object module : modules) { - String moduleName = getName.invoke(module); + String moduleName = (String) getName.invoke(module); if (moduleName.equals(name)) { res.add(module); } } } return res; - } catch (Exception e) { + } catch (Throwable e) { throw new GraalError(e); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java index 476e0ba8344..58bd9f1e93a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -28,11 +28,13 @@ import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases; import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; import java.util.ListIterator; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling; +import org.graalvm.compiler.hotspot.lir.VerifyMaxRegisterSizePhase; import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase; import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase; import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; @@ -139,6 +141,10 @@ public class HotSpotSuitesProvider extends SuitesProviderBase { StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), graph.getDebug(), AllowAssumptions.YES).method(graph.method()).build(); SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions())); + + if (graph.trackNodeSourcePosition()) { + targetGraph.setTrackNodeSourcePosition(); + } graphDecoder.decode(encodedGraph); } @@ -171,6 +177,9 @@ public class HotSpotSuitesProvider extends SuitesProviderBase { if (profileInstructions != null) { suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions)); } + if (Assertions.detailedAssertionsEnabled(options)) { + suites.getPostAllocationOptimizationStage().appendPhase(new VerifyMaxRegisterSizePhase(config.maxVectorSize)); + } return suites; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java index 55c0f35e87c..a918c30948d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java @@ -76,17 +76,17 @@ public class AOTInliningPolicy extends GreedyInliningPolicy { OptionValues options = info.graph().getOptions(); if (InlineEverything.getValue(options)) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); return true; } if (isIntrinsic(replacements, info)) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); return true; } if (info.shouldInline()) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); return true; } @@ -94,18 +94,18 @@ public class AOTInliningPolicy extends GreedyInliningPolicy { int nodes = info.determineNodeCount(); if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); return true; } double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus)); if (nodes <= maximumNodes) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, nodes, maximumNodes); return true; } - InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); + InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); return false; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java index b2f87bbc0aa..e600dcb1cf2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java @@ -86,7 +86,7 @@ public class AssertionSnippets implements Snippets { args.add("condition", assertionNode.condition()); args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")"); - template(assertionNode.getDebug(), args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args); + template(assertionNode, args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java index 6ea1cf5bcb4..a0d09fa130a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java @@ -87,7 +87,7 @@ public class HashCodeSnippets implements Snippets { StructuredGraph graph = node.graph(); Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage()); args.add("thisObj", node.object); - SnippetTemplate template = template(node.getDebug(), args); + SnippetTemplate template = template(node, args); template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java index 69e547306ec..585f4d33553 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java @@ -101,7 +101,7 @@ public class LoadExceptionObjectSnippets implements Snippets { } else { Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage()); args.addConst("threadRegister", registers.getThreadRegister()); - template(loadExceptionObject.getDebug(), args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args); + template(loadExceptionObject, args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java index 40fe62ea766..75509efba5d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java @@ -759,7 +759,7 @@ public class MonitorSnippets implements Snippets { args.addConst("counters", counters); } - template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); + template(monitorenterNode, args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); } public void lower(MonitorExitNode monitorexitNode, HotSpotRegistersProvider registers, LoweringTool tool) { @@ -778,7 +778,7 @@ public class MonitorSnippets implements Snippets { args.addConst("options", graph.getOptions()); args.addConst("counters", counters); - template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); + template(monitorexitNode, args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); } public static boolean isTracingEnabledForType(ValueNode object) { @@ -828,7 +828,7 @@ public class MonitorSnippets implements Snippets { invoke.setStateAfter(graph.start().stateAfter()); graph.addAfterFixed(graph.start(), invoke); - StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null); + StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null, invoke.graph().trackNodeSourcePosition(), invoke.getNodeSourcePosition()); InliningUtil.inline(invoke, inlineeGraph, false, null); List rets = graph.getNodes(ReturnNode.TYPE).snapshot(); @@ -846,7 +846,7 @@ public class MonitorSnippets implements Snippets { Arguments args = new Arguments(checkCounter, graph.getGuardsStage(), tool.getLoweringStage()); args.addConst("errMsg", msg); - inlineeGraph = template(graph.getDebug(), args).copySpecializedGraph(graph.getDebug()); + inlineeGraph = template(invoke, args).copySpecializedGraph(graph.getDebug()); InliningUtil.inline(invoke, inlineeGraph, false, null); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java index 3cb35efd94c..467f8f98aee 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java @@ -626,7 +626,7 @@ public class NewObjectSnippets implements Snippets { args.addConst("options", localOptions); args.addConst("counters", counters); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(newInstanceNode, args); graph.getDebug().log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args); } @@ -669,7 +669,7 @@ public class NewObjectSnippets implements Snippets { args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : ""); args.addConst("options", localOptions); args.addConst("counters", counters); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(newArrayNode, args); graph.getDebug().log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); } @@ -686,7 +686,7 @@ public class NewObjectSnippets implements Snippets { args.addConst("options", localOptions); args.addConst("counters", counters); - SnippetTemplate template = template(newInstanceNode.getDebug(), args); + SnippetTemplate template = template(newInstanceNode, args); template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args); } @@ -715,7 +715,7 @@ public class NewObjectSnippets implements Snippets { args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord()); args.addConst("options", localOptions); args.addConst("counters", counters); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(newArrayNode, args); template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); } @@ -739,7 +739,7 @@ public class NewObjectSnippets implements Snippets { args.add("hub", hub); args.addConst("rank", rank); args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims); - template(newmultiarrayNode.getDebug(), args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args); + template(newmultiarrayNode, args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args); } private static int instanceSize(HotSpotResolvedObjectType type) { @@ -753,7 +753,7 @@ public class NewObjectSnippets implements Snippets { Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage()); args.addConst("threadRegister", registers.getThreadRegister()); - SnippetTemplate template = template(verifyHeapNode.getDebug(), args); + SnippetTemplate template = template(verifyHeapNode, args); template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args); } else { GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java index 02bf3438173..032a5a85da0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java @@ -86,7 +86,7 @@ public final class ObjectCloneNode extends BasicObjectCloneNode implements Virtu StructuredGraph snippetGraph = null; DebugContext debug = getDebug(); try (DebugContext.Scope s = debug.scope("ArrayCloneSnippet", snippetMethod)) { - snippetGraph = replacements.getSnippet(snippetMethod, null); + snippetGraph = replacements.getSnippet(snippetMethod, null, graph().trackNodeSourcePosition(), this.getNodeSourcePosition()); } catch (Throwable e) { throw debug.handle(e); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java index f6c9bb75826..d5131e802e3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java @@ -83,7 +83,7 @@ public class StringToBytesSnippets implements Snippets { public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) { Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage()); args.addConst("compilationTimeString", stringToBytesNode.getValue()); - SnippetTemplate template = template(stringToBytesNode.getDebug(), args); + SnippetTemplate template = template(stringToBytesNode, args); template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java index 31d343bb950..d29b2f81484 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java @@ -65,7 +65,7 @@ public class UnsafeLoadSnippets implements Snippets { Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage()); args.add("object", load.object()); args.add("offset", load.offset()); - template(load.getDebug(), args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args); + template(load, args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java index 36ffe5ab386..5682da564a6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java @@ -434,7 +434,7 @@ public class WriteBarrierSnippets implements Snippets { args.add("object", address.getBase()); } args.addConst("counters", counters); - template(writeBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args); + template(writeBarrier, args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args); } public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) { @@ -442,7 +442,7 @@ public class WriteBarrierSnippets implements Snippets { args.add("address", arrayRangeWriteBarrier.getAddress()); args.add("length", arrayRangeWriteBarrier.getLength()); args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); - template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); + template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) { @@ -467,7 +467,7 @@ public class WriteBarrierSnippets implements Snippets { args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("trace", traceBarrier(writeBarrierPre.graph())); args.addConst("counters", counters); - template(writeBarrierPre.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args); + template(writeBarrierPre, args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args); } public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { @@ -492,7 +492,7 @@ public class WriteBarrierSnippets implements Snippets { args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("trace", traceBarrier(readBarrier.graph())); args.addConst("counters", counters); - template(readBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args); + template(readBarrier, args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args); } public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) { @@ -522,7 +522,7 @@ public class WriteBarrierSnippets implements Snippets { args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("trace", traceBarrier(writeBarrierPost.graph())); args.addConst("counters", counters); - template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args); + template(writeBarrierPost, args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args); } public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { @@ -531,7 +531,7 @@ public class WriteBarrierSnippets implements Snippets { args.add("length", arrayRangeWriteBarrier.getLength()); args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); args.addConst("threadRegister", registers.getThreadRegister()); - template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); + template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { @@ -540,7 +540,7 @@ public class WriteBarrierSnippets implements Snippets { args.add("length", arrayRangeWriteBarrier.getLength()); args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); args.addConst("threadRegister", registers.getThreadRegister()); - template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); + template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java index 47d8985acac..22524819bc5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java @@ -36,10 +36,10 @@ import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall; import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall; import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; @@ -141,7 +141,7 @@ public class ResolveConstantSnippets implements Snippets { Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); args.add("constant", value); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(resolveConstantNode, args); template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); assert resolveConstantNode.hasNoUsages(); @@ -180,7 +180,7 @@ public class ResolveConstantSnippets implements Snippets { Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); args.add("constant", value); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(resolveConstantNode, args); template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); assert resolveConstantNode.hasNoUsages(); @@ -200,7 +200,7 @@ public class ResolveConstantSnippets implements Snippets { Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage()); args.add("constant", value); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(initializeKlassNode, args); template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args); assert initializeKlassNode.hasNoUsages(); if (!initializeKlassNode.isDeleted()) { @@ -218,7 +218,7 @@ public class ResolveConstantSnippets implements Snippets { Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage()); args.add("method", method); args.add("klassHint", resolveMethodAndLoadCountersNode.getHub()); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(resolveMethodAndLoadCountersNode, args); template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args); assert resolveMethodAndLoadCountersNode.hasNoUsages(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java index 94289adc6d4..72e435ed235 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java @@ -524,7 +524,7 @@ public class ArrayCopySnippets implements Snippets { */ private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) { StructuredGraph graph = arraycopy.graph(); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(arraycopy, args); UnmodifiableEconomicMap replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args, false); for (Node originalNode : replacements.getKeys()) { if (originalNode instanceof Invoke) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java index a13ef3c69f3..b557db4ac40 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java @@ -150,7 +150,7 @@ public class ProbabilisticProfileSnippets implements Snippets { args.add("bci", bci); args.add("targetBci", targetBci); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(profileNode, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); } else if (profileNode instanceof ProfileInvokeNode) { ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; @@ -163,7 +163,7 @@ public class ProbabilisticProfileSnippets implements Snippets { args.add("stepLog", stepLog); args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); args.addConst("probLog", profileInvokeNode.getProbabilityLog()); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(profileNode, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); } else { throw new GraalError("Unsupported profile node type: " + profileNode); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java index 79d21ab15ee..1986657f3b6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java @@ -132,7 +132,7 @@ public class ProfileSnippets implements Snippets { args.add("bci", bci); args.add("targetBci", targetBci); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(profileNode, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); } else if (profileNode instanceof ProfileInvokeNode) { ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; @@ -142,7 +142,7 @@ public class ProfileSnippets implements Snippets { args.add("step", step); args.add("stepLog", stepLog); args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); - SnippetTemplate template = template(graph.getDebug(), args); + SnippetTemplate template = template(profileNode, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); } else { throw new GraalError("Unsupported profile node type: " + profileNode); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java index d817dd3c03b..e41bc188819 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java @@ -34,8 +34,11 @@ import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.JavaMethodContext; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; @@ -224,33 +227,37 @@ public class ForeignCallStub extends Stub { * %r15 on AMD64) and is only prepended if {@link #prependThread} is true. */ @Override + @SuppressWarnings("try") protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier compilationId) { WordTypes wordTypes = providers.getWordTypes(); Class[] args = linkage.getDescriptor().getArgumentTypes(); boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn()); StructuredGraph graph = new StructuredGraph.Builder(options, debug).name(toString()).compilationId(compilationId).build(); graph.disableUnsafeAccessTracking(); + graph.setTrackNodeSourcePosition(); + try { + ResolvedJavaMethod thisMethod = providers.getMetaAccess().lookupJavaMethod(ForeignCallStub.class.getDeclaredMethod("getGraph", DebugContext.class, CompilationIdentifier.class)); + try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(thisMethod))) { + GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); + ParameterNode[] params = createParameters(kit, args); + ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); + ValueNode result = createTargetCall(kit, params, thread); + kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); + if (isObjectResult) { + InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); + result = kit.createInvoke(StubUtil.class, "verifyObject", object); + } + kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); + debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph"); - GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); - ParameterNode[] params = createParameters(kit, args); + kit.inlineInvokes(); + new RemoveValueProxyPhase().apply(graph); - ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); - ValueNode result = createTargetCall(kit, params, thread); - kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); - if (isObjectResult) { - InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); - result = kit.createInvoke(StubUtil.class, "verifyObject", object); + debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation"); + } + } catch (Exception e) { + throw GraalError.shouldNotReachHere(e); } - kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); - - debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph"); - - kit.inlineInvokes(); - - new RemoveValueProxyPhase().apply(graph); - - debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation"); - return graph; } 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 cf239a1cd62..45b7da7cec6 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 @@ -279,6 +279,7 @@ import org.graalvm.compiler.bytecode.Bytecodes; import org.graalvm.compiler.bytecode.Bytes; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; @@ -678,6 +679,8 @@ public class BytecodeParser implements GraphBuilderContext { private boolean finalBarrierRequired; private ValueNode originalReceiver; + private final boolean eagerInitializing; + private final boolean uninitializedIsError; protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { @@ -701,6 +704,14 @@ public class BytecodeParser implements GraphBuilderContext { this.entryBCI = entryBCI; this.parent = parent; + ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && graphBuilderConfig.eagerResolving()) { + uninitializedIsError = eagerInitializing = !classInitializationPlugin.supportsLazyInitialization(constantPool); + } else { + eagerInitializing = graphBuilderConfig.eagerResolving(); + uninitializedIsError = graphBuilderConfig.unresolvedIsError(); + } + assert code.getCode() != null : "method must contain bytecodes: " + method; if (TraceBytecodeParserLevel.getValue(options) != 0) { @@ -713,6 +724,11 @@ public class BytecodeParser implements GraphBuilderContext { lnt = code.getLineNumberTable(); previousLineNumber = -1; } + + assert !GraalOptions.TrackNodeSourcePosition.getValue(options) || graph.trackNodeSourcePosition(); + if (graphBuilderConfig.trackNodeSourcePosition() || (parent != null && parent.graph.trackNodeSourcePosition())) { + graph.setTrackNodeSourcePosition(); + } } protected GraphBuilderPhase.Instance getGraphBuilderInstance() { @@ -807,26 +823,28 @@ public class BytecodeParser implements GraphBuilderContext { } } - if (method.isSynchronized()) { - finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI); + try (DebugCloseable context = openNodeContext()) { + if (method.isSynchronized()) { + finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI); - // add a monitor enter to the start block - methodSynchronizedObject = synchronizedObject(frameState, method); - frameState.clearNonLiveLocals(startBlock, liveness, true); - assert bci() == 0; - genMonitorEnter(methodSynchronizedObject, bci()); + // add a monitor enter to the start block + methodSynchronizedObject = synchronizedObject(frameState, method); + frameState.clearNonLiveLocals(startBlock, liveness, true); + assert bci() == 0; + genMonitorEnter(methodSynchronizedObject, bci()); + } + + ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + profilingPlugin.profileInvoke(this, method, stateBefore); + } + + finishPrepare(lastInstr, 0); + + genInfoPointNode(InfopointReason.METHOD_START, null); } - ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); - profilingPlugin.profileInvoke(this, method, stateBefore); - } - - finishPrepare(lastInstr, 0); - - genInfoPointNode(InfopointReason.METHOD_START, null); - currentBlock = blockMap.getStartBlock(); setEntryState(startBlock, frameState); if (startBlock.isLoopHeader) { @@ -1338,6 +1356,8 @@ public class BytecodeParser implements GraphBuilderContext { protected void genInvokeStatic(int cpi, int opcode) { JavaMethod target = lookupMethod(cpi, opcode); + assert !uninitializedIsError || + (target instanceof ResolvedJavaMethod && ((ResolvedJavaMethod) target).getDeclaringClass().isInitialized()) : target; genInvokeStatic(target); } @@ -2017,6 +2037,7 @@ public class BytecodeParser implements GraphBuilderContext { } } + @SuppressWarnings("try") protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); if (plugin != null) { @@ -2041,11 +2062,13 @@ public class BytecodeParser implements GraphBuilderContext { } InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; - if (plugin.execute(this, targetMethod, pluginReceiver, args)) { - afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); - return true; - } else { - afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); + try (DebugCloseable context = openNodeContext(targetMethod)) { + if (plugin.execute(this, targetMethod, pluginReceiver, args)) { + afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); + return true; + } else { + afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); + } } } return false; @@ -2112,6 +2135,7 @@ public class BytecodeParser implements GraphBuilderContext { * Tries to inline {@code targetMethod} if it is an instance field accessor. This avoids the * overhead of creating and using a nested {@link BytecodeParser} object. */ + @SuppressWarnings("try") private boolean tryFastInlineAccessor(ValueNode[] args, ResolvedJavaMethod targetMethod) { byte[] bytecode = targetMethod.getCode(); if (bytecode != null && bytecode.length == ACCESSOR_BYTECODE_LENGTH && @@ -2124,10 +2148,12 @@ public class BytecodeParser implements GraphBuilderContext { if (field instanceof ResolvedJavaField) { ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get(); ResolvedJavaField resolvedField = (ResolvedJavaField) field; - genGetField(resolvedField, receiver); - notifyBeforeInline(targetMethod); - printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)"); - notifyAfterInline(targetMethod); + try (DebugCloseable context = openNodeContext(targetMethod, 1)) { + genGetField(resolvedField, receiver); + notifyBeforeInline(targetMethod); + printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)"); + notifyAfterInline(targetMethod); + } return true; } } @@ -2562,6 +2588,7 @@ public class BytecodeParser implements GraphBuilderContext { @Override public T append(T v) { + assert !graph.trackNodeSourcePosition() || graph.currentNodeSourcePosition() != null || currentBlock == blockMap.getUnwindBlock() || currentBlock instanceof ExceptionDispatchBlock; if (v.graph() != null) { return v; } @@ -2670,93 +2697,97 @@ public class BytecodeParser implements GraphBuilderContext { return createTarget(block, state, false, false); } + @SuppressWarnings("try") private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { assert block != null && state != null; assert !block.isExceptionEntry || state.stackSize() == 1; - if (getFirstInstruction(block) == null) { - /* - * This is the first time we see this block as a branch target. Create and return a - * placeholder that later can be replaced with a MergeNode when we see this block again. - */ - FixedNode targetNode; - if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) { - setFirstInstruction(block, lastInstr); - lastInstr = null; - } else { - setFirstInstruction(block, graph.add(new BeginNode())); - } - targetNode = getFirstInstruction(block); - Target target = checkLoopExit(targetNode, block, state); - FixedNode result = target.fixed; - FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; - setEntryState(block, currentEntryState); - currentEntryState.clearNonLiveLocals(block, liveness, true); + try (DebugCloseable context = openNodeContext(state, block.startBci)) { + if (getFirstInstruction(block) == null) { + /* + * This is the first time we see this block as a branch target. Create and return a + * placeholder that later can be replaced with a MergeNode when we see this block + * again. + */ + FixedNode targetNode; + if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) { + setFirstInstruction(block, lastInstr); + lastInstr = null; + } else { + setFirstInstruction(block, graph.add(new BeginNode())); + } + targetNode = getFirstInstruction(block); + Target target = checkLoopExit(targetNode, block, state); + FixedNode result = target.fixed; + FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; + setEntryState(block, currentEntryState); + currentEntryState.clearNonLiveLocals(block, liveness, true); - debug.log("createTarget %s: first visit, result: %s", block, targetNode); - return result; - } - - // We already saw this block before, so we have to merge states. - if (!getEntryState(block).isCompatibleWith(state)) { - throw bailout("stacks do not match; bytecodes would not verify"); - } - - if (getFirstInstruction(block) instanceof LoopBeginNode) { - assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch"; - /* - * Backward loop edge. We need to create a special LoopEndNode and merge with the loop - * begin node created before. - */ - LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block); - LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); - Target target = checkLoopExit(loopEnd, block, state); - FixedNode result = target.fixed; - getEntryState(block).merge(loopBegin, target.state); - - debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); - return result; - } - assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; - assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block"; - - if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) { - /* - * This is the second time we see this block. Create the actual MergeNode and the End - * Node for the already existing edge. - */ - AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block); - - // The EndNode for the already existing edge. - EndNode end = graph.add(new EndNode()); - // The MergeNode that replaces the placeholder. - AbstractMergeNode mergeNode = graph.add(new MergeNode()); - FixedNode next = beginNode.next(); - - if (beginNode.predecessor() instanceof ControlSplitNode) { - beginNode.setNext(end); - } else { - beginNode.replaceAtPredecessor(end); - beginNode.safeDelete(); + debug.log("createTarget %s: first visit, result: %s", block, targetNode); + return result; } - mergeNode.addForwardEnd(end); - mergeNode.setNext(next); + // We already saw this block before, so we have to merge states. + if (!getEntryState(block).isCompatibleWith(state)) { + throw bailout("stacks do not match; bytecodes would not verify"); + } - setFirstInstruction(block, mergeNode); + if (getFirstInstruction(block) instanceof LoopBeginNode) { + assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch"; + /* + * Backward loop edge. We need to create a special LoopEndNode and merge with the + * loop begin node created before. + */ + LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block); + LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); + Target target = checkLoopExit(loopEnd, block, state); + FixedNode result = target.fixed; + getEntryState(block).merge(loopBegin, target.state); + + debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); + return result; + } + assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; + assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block"; + + if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) { + /* + * This is the second time we see this block. Create the actual MergeNode and the + * End Node for the already existing edge. + */ + AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block); + + // The EndNode for the already existing edge. + EndNode end = graph.add(new EndNode()); + // The MergeNode that replaces the placeholder. + AbstractMergeNode mergeNode = graph.add(new MergeNode()); + FixedNode next = beginNode.next(); + + if (beginNode.predecessor() instanceof ControlSplitNode) { + beginNode.setNext(end); + } else { + beginNode.replaceAtPredecessor(end); + beginNode.safeDelete(); + } + + mergeNode.addForwardEnd(end); + mergeNode.setNext(next); + + setFirstInstruction(block, mergeNode); + } + + AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block); + + // The EndNode for the newly merged edge. + EndNode newEnd = graph.add(new EndNode()); + Target target = checkLoopExit(newEnd, block, state); + FixedNode result = target.fixed; + getEntryState(block).merge(mergeNode, target.state); + mergeNode.addForwardEnd(newEnd); + + debug.log("createTarget %s: merging state, result: %s", block, result); + return result; } - - AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block); - - // The EndNode for the newly merged edge. - EndNode newEnd = graph.add(new EndNode()); - Target target = checkLoopExit(newEnd, block, state); - FixedNode result = target.fixed; - getEntryState(block).merge(mergeNode, target.state); - mergeNode.addForwardEnd(newEnd); - - debug.log("createTarget %s: merging state, result: %s", block, result); - return result; } /** @@ -2965,28 +2996,28 @@ public class BytecodeParser implements GraphBuilderContext { } while (bci < endBCI) { - if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { - currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1; - if (currentLineNumber != previousLineNumber) { - genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); - previousLineNumber = currentLineNumber; - } - } - - // read the opcode - int opcode = stream.currentBC(); - assert traceState(); - assert traceInstruction(bci, opcode, bci == block.startBci); - if (parent == null && bci == entryBCI) { - if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) { - throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported"); - } - EntryMarkerNode x = append(new EntryMarkerNode()); - frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x))); - x.setStateAfter(createFrameState(bci, x)); - } - try (DebugCloseable context = openNodeContext()) { + if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { + currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1; + if (currentLineNumber != previousLineNumber) { + genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); + previousLineNumber = currentLineNumber; + } + } + + // read the opcode + int opcode = stream.currentBC(); + assert traceState(); + assert traceInstruction(bci, opcode, bci == block.startBci); + if (parent == null && bci == entryBCI) { + if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) { + throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported"); + } + EntryMarkerNode x = append(new EntryMarkerNode()); + frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x))); + x.setStateAfter(createFrameState(bci, x)); + } + processBytecode(bci, opcode); } catch (BailoutException e) { // Don't wrap bailouts as parser errors @@ -3017,13 +3048,28 @@ public class BytecodeParser implements GraphBuilderContext { } } - private DebugCloseable openNodeContext() { - if ((graphBuilderConfig.trackNodeSourcePosition() || debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) { - return graph.withNodeSourcePosition(createBytecodePosition()); + private DebugCloseable openNodeContext(FrameStateBuilder state, int startBci) { + if (graph.trackNodeSourcePosition()) { + return graph.withNodeSourcePosition(state.createBytecodePosition(startBci)); } return null; } + private DebugCloseable openNodeContext(ResolvedJavaMethod targetMethod) { + return openNodeContext(targetMethod, -1); + } + + private DebugCloseable openNodeContext(ResolvedJavaMethod targetMethod, int bci) { + if (graph.trackNodeSourcePosition()) { + return graph.withNodeSourcePosition(new NodeSourcePosition(createBytecodePosition(), targetMethod, bci)); + } + return null; + } + + private DebugCloseable openNodeContext() { + return openNodeContext(frameState, bci()); + } + /* Also a hook for subclasses. */ protected boolean forceLoopPhis() { return graph.isOSR(); @@ -3133,7 +3179,7 @@ public class BytecodeParser implements GraphBuilderContext { genIf(condition, trueSuccessor, falseSuccessor, probability); } - private double getProfileProbability(boolean negate) { + protected double getProfileProbability(boolean negate) { double probability; if (profilingInfo == null) { probability = 0.5; @@ -3433,7 +3479,8 @@ public class BytecodeParser implements GraphBuilderContext { } protected NodeSourcePosition createBytecodePosition() { - return frameState.createBytecodePosition(bci()); + NodeSourcePosition bytecodePosition = frameState.createBytecodePosition(bci()); + return bytecodePosition; } public void setCurrentFrameState(FrameStateBuilder frameState) { @@ -3454,6 +3501,7 @@ public class BytecodeParser implements GraphBuilderContext { frameState.push(kind, value); } + @SuppressWarnings("try") public void loadLocalObject(int index) { ValueNode value = frameState.loadLocal(index, JavaKind.Object); @@ -3461,7 +3509,9 @@ public class BytecodeParser implements GraphBuilderContext { int nextBC = stream.readUByte(nextBCI); if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) { stream.next(); - genGetField(stream.readCPI(), Bytecodes.GETFIELD, value); + try (DebugCloseable ignored = openNodeContext()) { + genGetField(stream.readCPI(), Bytecodes.GETFIELD, value); + } } else { frameState.push(JavaKind.Object, value); } @@ -3689,6 +3739,17 @@ public class BytecodeParser implements GraphBuilderContext { genIf(x, cond, y); } + private static void initialize(ResolvedJavaType resolvedType) { + /* + * Since we're potentially triggering class initialization here, we need synchronization to + * mitigate the potential for class initialization related deadlock being caused by the + * compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550). + */ + synchronized (BytecodeParser.class) { + resolvedType.initialize(); + } + } + protected JavaType lookupType(int cpi, int bytecode) { maybeEagerlyResolve(cpi, bytecode); JavaType result = constantPool.lookupType(cpi, bytecode); @@ -3699,32 +3760,26 @@ public class BytecodeParser implements GraphBuilderContext { private JavaMethod lookupMethod(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaMethod result = constantPool.lookupMethod(cpi, opcode); - /* - * In general, one cannot assume that the declaring class being initialized is useful, since - * the actual concrete receiver may be a different class (except for static calls). Also, - * interfaces are initialized only under special circumstances, so that this assertion would - * often fail for interface calls. - */ - assert !graphBuilderConfig.unresolvedIsError() || - (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : result; return result; } protected JavaField lookupField(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaField result = constantPool.lookupField(cpi, method, opcode); - - if (graphBuilderConfig.eagerResolving()) { - assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result; + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result; + if (parsingIntrinsic() || eagerInitializing) { if (result instanceof ResolvedJavaField) { ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); if (!declaringClass.isInitialized()) { - assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; - declaringClass.initialize(); + // Even with eager initialization, superinterfaces are not always initialized. + // See StaticInterfaceFieldTest + assert !eagerInitializing || declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; + initialize(declaringClass); } } } - assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + assert !uninitializedIsError || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; return result; } @@ -3745,7 +3800,12 @@ public class BytecodeParser implements GraphBuilderContext { * the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550). */ synchronized (BytecodeParser.class) { - constantPool.loadReferencedType(cpi, bytecode); + ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null) { + classInitializationPlugin.loadReferencedType(this, constantPool, cpi, bytecode); + } else { + constantPool.loadReferencedType(cpi, bytecode); + } } } } @@ -3872,11 +3932,16 @@ public class BytecodeParser implements GraphBuilderContext { } void genNewInstance(JavaType type) { - if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { + if (!(type instanceof ResolvedJavaType)) { handleUnresolvedNewInstance(type); return; } ResolvedJavaType resolvedType = (ResolvedJavaType) type; + ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (!resolvedType.isInitialized() && classInitializationPlugin == null) { + handleUnresolvedNewInstance(type); + return; + } ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); if (skippedExceptionTypes != null) { @@ -3888,7 +3953,6 @@ public class BytecodeParser implements GraphBuilderContext { } } - ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) { FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); classInitializationPlugin.apply(this, resolvedType, stateBefore); @@ -4078,7 +4142,7 @@ public class BytecodeParser implements GraphBuilderContext { } } - private boolean needsExplicitException() { + protected boolean needsExplicitException() { BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode(); if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) { return true; @@ -4163,7 +4227,7 @@ public class BytecodeParser implements GraphBuilderContext { private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) { if (field instanceof ResolvedJavaField) { ResolvedJavaField resolvedField = (ResolvedJavaField) field; - if (resolvedField.getDeclaringClass().isInitialized()) { + if (resolvedField.getDeclaringClass().isInitialized() || graphBuilderConfig.getPlugins().getClassInitializationPlugin() != null) { return resolvedField; } /* diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java index ad3c28120ee..53d6074f2e8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java @@ -58,7 +58,7 @@ public class BytecodeParserOptions { public static final OptionKey TraceParserPlugins = new OptionKey<>(false); @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) - public static final OptionKey InlineDuringParsingMaxDepth = new OptionKey<>(3); + public static final OptionKey InlineDuringParsingMaxDepth = new OptionKey<>(10); @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) public static final OptionKey HideSubstitutionStates = new OptionKey<>(false); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java index 2787bbaec1f..0e5d1712def 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java @@ -32,7 +32,6 @@ import static org.graalvm.compiler.bytecode.Bytecodes.POP; import static org.graalvm.compiler.bytecode.Bytecodes.POP2; import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; -import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates; import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER; import java.util.ArrayList; @@ -74,7 +73,6 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.Assumptions; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -112,8 +110,6 @@ public final class FrameStateBuilder implements SideEffectsState { */ private List sideEffects; - private JavaConstant constantReceiver; - /** * Creates a new frame state builder for the given method and the given target graph. * @@ -164,7 +160,6 @@ public final class FrameStateBuilder implements SideEffectsState { locals[javaIndex] = arguments[index]; javaIndex = 1; index = 1; - constantReceiver = locals[0].asJavaConstant(); } Signature sig = getMethod().getSignature(); int max = sig.getParameterCount(false); @@ -310,7 +305,7 @@ public final class FrameStateBuilder implements SideEffectsState { public FrameState create(int bci, StateSplit forStateSplit) { if (parser != null && parser.parsingIntrinsic()) { - NodeSourcePosition sourcePosition = createBytecodePosition(bci, false); + NodeSourcePosition sourcePosition = parser.getGraph().trackNodeSourcePosition() ? createBytecodePosition(bci) : null; return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit, sourcePosition); } @@ -354,25 +349,14 @@ public final class FrameStateBuilder implements SideEffectsState { } public NodeSourcePosition createBytecodePosition(int bci) { - return createBytecodePosition(bci, HideSubstitutionStates.getValue(parser.graph.getOptions())); - } - - private NodeSourcePosition createBytecodePosition(int bci, boolean hideSubstitutionStates) { BytecodeParser parent = parser.getParent(); - if (hideSubstitutionStates) { - if (parser.parsingIntrinsic()) { - // Attribute to the method being replaced - return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1); - } - // Skip intrinsic frames - parent = parser.getNonIntrinsicAncestor(); - } - return create(constantReceiver, bci, parent, hideSubstitutionStates); + NodeSourcePosition position = create(bci, parent); + return position; } - private NodeSourcePosition create(JavaConstant receiver, int bci, BytecodeParser parent, boolean hideSubstitutionStates) { + private NodeSourcePosition create(int bci, BytecodeParser parent) { if (outerSourcePosition == null && parent != null) { - outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci(), hideSubstitutionStates); + outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci()); } if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { return FrameState.toSourcePosition(outerFrameState); @@ -380,7 +364,7 @@ public final class FrameStateBuilder implements SideEffectsState { if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { throw shouldNotReachHere(); } - return new NodeSourcePosition(receiver, outerSourcePosition, code.getMethod(), bci); + return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci); } public FrameStateBuilder copy() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java index f9c1c35d7c9..2adecca4ef2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java @@ -22,25 +22,14 @@ */ package org.graalvm.compiler.jtt; -import static java.lang.reflect.Modifier.isStatic; - import java.util.Collections; import java.util.Set; import org.graalvm.compiler.core.test.GraalCompilerTest; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.ParameterNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.Builder; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.tiers.HighTierContext; import org.junit.Assert; -import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -66,45 +55,35 @@ public class JTTTest extends GraalCompilerTest { } @Override - protected StructuredGraph parse(Builder builder, PhaseSuite graphBuilderSuite) { - StructuredGraph graph = super.parse(builder, graphBuilderSuite); - if (argsToBind != null) { - ResolvedJavaMethod m = graph.method(); - Object receiver = isStatic(m.getModifiers()) ? null : this; - Object[] args = argsWithReceiver(receiver, argsToBind); - JavaType[] parameterTypes = m.toParameterTypes(); - assert parameterTypes.length == args.length; - for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { - JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]); - ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph); - param.replaceAtUsages(replacement); - } - } - return graph; + protected Object[] getArgumentToBind() { + return argsToBind; } - @Override - protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) { - return super.getCode(method, graph, argsToBind != null, installAsDefault, options); - } - - Double delta; + /** + * If non-null, then this is a test for a method returning a {@code double} value that must be + * within {@code ulpDelta}s of the expected value. + */ + protected Double ulpDelta; @Override protected void assertDeepEquals(Object expected, Object actual) { - if (delta != null) { - Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta); + if (ulpDelta != null) { + double expectedDouble = (double) expected; + double actualDouble = (Double) actual; + double ulp = Math.ulp(expectedDouble); + double delta = ulpDelta * ulp; + try { + Assert.assertEquals(expectedDouble, actualDouble, delta); + } catch (AssertionError e) { + double diff = Math.abs(expectedDouble - actualDouble); + double diffUlps = diff / ulp; + throw new AssertionError(e.getMessage() + " // " + diffUlps + " ulps"); + } } else { super.assertDeepEquals(expected, actual); } } - @SuppressWarnings("hiding") - protected void runTestWithDelta(double delta, String name, Object... args) { - this.delta = Double.valueOf(delta); - runTest(name, args); - } - protected void runTest(String name, Object... args) { runTest(getInitialOptions(), name, args); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java index b3d341d8031..a06d4764c2c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java @@ -24,10 +24,8 @@ package org.graalvm.compiler.jtt.hotpath; -import org.junit.Ignore; -import org.junit.Test; - import org.graalvm.compiler.jtt.JTTTest; +import org.junit.Test; /* */ @@ -101,17 +99,16 @@ public class HP_series extends JTTTest { return (0.0); } - /* - * This test is sensible to the implementation of Math.pow, cos and sin. Since for these - * functions, the specs says "The computed result must be within 1 ulp of the exact result", - * different implementation may return different results. The 11 ulp delta allowed for test(100) - * tries to account for that but is not guaranteed to work forever. + /** + * This test is sensitive to the implementation of {@link Math#pow}, {@link Math#cos} and + * {@link Math#sin(double)}. Since for these functions, the specs says "The computed result must + * be within 1 ulp of the exact result", different implementation may return different results. + * The 11 ulp delta allowed for test(100) tries to account for that but is not guaranteed to + * work forever. */ - @Ignore("failure-prone because of the variabiliy of pow/cos/sin") @Test public void run0() throws Throwable { - double expected = 0.6248571921291398d; - runTestWithDelta(11 * Math.ulp(expected), "test", 100); + ulpDelta = 11.0D; + runTest("test", 100); } - } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java index 8e204621ed0..ec040306d3f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java @@ -22,13 +22,14 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ -public class Math_abs extends JTTTest { +public class Math_abs extends UnaryMath { @SuppressWarnings("serial") public static class NaN extends Throwable { @@ -78,4 +79,10 @@ public class Math_abs extends JTTTest { runTest("test", java.lang.Double.NaN); } + @Test + public void run7() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + testManyValues(options, method); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java index 7ec9f38120a..d69efba302f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java @@ -22,13 +22,14 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ -public class Math_cos extends JTTTest { +public class Math_cos extends UnaryMath { @SuppressWarnings("serial") public static class NaN extends Throwable { @@ -58,4 +59,10 @@ public class Math_cos extends JTTTest { runTest("test", java.lang.Double.POSITIVE_INFINITY); } + @Test + public void run3() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + testManyValues(options, method); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java index 7824eee8acb..40ce6cfa0a3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java @@ -22,14 +22,12 @@ */ package org.graalvm.compiler.jtt.lang; -import org.junit.Ignore; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; - /* */ -public class Math_exp extends JTTTest { +public class Math_exp extends UnaryMath { public static double test(double arg) { return Math.exp(arg); @@ -65,9 +63,19 @@ public class Math_exp extends JTTTest { runTest("test", 0.0D); } - @Ignore("java.lang.AssertionError: expected:<2.718281828459045> but was:<2.7182818284590455>") @Test public void run6() { runTest("test", 1.0D); } + + @Test + public void run7() { + runTest("test", -1024D); + } + + @Test + public void run8() { + OptionValues options = getInitialOptions(); + testManyValues(options, getResolvedJavaMethod("test")); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java index 02a126cb1d7..740a9456bdf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java @@ -22,13 +22,14 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ -public class Math_log extends JTTTest { +public class Math_log extends UnaryMath { @SuppressWarnings("serial") public static class NaN extends Throwable { @@ -78,4 +79,10 @@ public class Math_log extends JTTTest { runTest("test", -0.0d); } + @Test + public void run7() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + testManyValues(options, method); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java index 0ad21ba424f..6fb0b977450 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java @@ -22,9 +22,11 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ @@ -88,4 +90,44 @@ public class Math_pow extends JTTTest { public void run10() throws Throwable { runTest("test", 0.999998, 1500000.0); } + + private static final long STEP = Long.MAX_VALUE / 1_000_000; + + @Test + public void run11() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + Object receiver = null; + long testIteration = 0; + for (long l = Long.MIN_VALUE;; l += STEP) { + double x = Double.longBitsToDouble(l); + double y = x; + testOne(options, method, receiver, testIteration, l, x, y); + y = l < 0 ? Double.longBitsToDouble(Long.MAX_VALUE + l) : Double.longBitsToDouble(Long.MAX_VALUE - l); + testOne(options, method, receiver, testIteration, l, x, y); + if (Long.MAX_VALUE - STEP < l) { + break; + } + testIteration++; + } + } + + @Test + public void run12() { + long l = 4355599093822972882L; + double x = Double.longBitsToDouble(l); + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + Object receiver = null; + testOne(options, method, receiver, 1, l, x, x); + } + + private void testOne(OptionValues options, ResolvedJavaMethod method, Object receiver, long testIteration, long l, double x, double y) throws AssertionError { + Result expect = executeExpected(method, receiver, x, y); + try { + testAgainstExpected(options, method, expect, EMPTY, receiver, x, y); + } catch (AssertionError e) { + throw new AssertionError(String.format("%d: While testing %g [long: %d, hex: %x]", testIteration, x, l, l), e); + } + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java index 07a1b2a9d01..1c6abfa727c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java @@ -22,13 +22,14 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ -public class Math_sin extends JTTTest { +public class Math_sin extends UnaryMath { @SuppressWarnings("serial") public static class NaN extends Throwable { @@ -83,4 +84,10 @@ public class Math_sin extends JTTTest { runTest("test", 0.0d); } + @Test + public void run5() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + testManyValues(options, method); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java index d8d401604d6..66b39b5fc49 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java @@ -22,13 +22,14 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ -public class Math_sqrt extends JTTTest { +public class Math_sqrt extends UnaryMath { @SuppressWarnings("serial") public static class NaN extends Throwable { @@ -78,4 +79,10 @@ public class Math_sqrt extends JTTTest { runTest("test", -0.0d); } + @Test + public void run7() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + testManyValues(options, method); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java index e49aeb7832b..96a59456c54 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java @@ -22,13 +22,14 @@ */ package org.graalvm.compiler.jtt.lang; +import org.graalvm.compiler.options.OptionValues; import org.junit.Test; -import org.graalvm.compiler.jtt.JTTTest; +import jdk.vm.ci.meta.ResolvedJavaMethod; /* */ -public class Math_tan extends JTTTest { +public class Math_tan extends UnaryMath { @SuppressWarnings("serial") public static class NaN extends Throwable { @@ -68,4 +69,10 @@ public class Math_tan extends JTTTest { runTest("test", 0.0d); } + @Test + public void run5() { + OptionValues options = getInitialOptions(); + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + testManyValues(options, method); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java new file mode 100644 index 00000000000..5304e61fe0c --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.jtt.lang; + +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.options.OptionValues; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public abstract class UnaryMath extends JTTTest { + + private static final long STEP = Long.MAX_VALUE / 1_000_000; + + /** + * Tests a unary {@link Math} method on a wide range of values. + */ + void testManyValues(OptionValues options, ResolvedJavaMethod method) throws AssertionError { + if (!Java8OrEarlier) { + /* + * GR-8276: Allow for variance on JVMCI > 8 until a JVMCI version that includes + * https://github.com/graalvm/graal-jvmci-8/commit/ + * c86fb66f86b8d52a08dd2495d34879d3730f9987 or Graal has stubs that a monotonic with + * other HotSpot implementations of these Math routines. + */ + ulpDelta = 2D; + } else { + /* + * Forces the assertion message shows the ulps by which a computed result is wrong. + */ + ulpDelta = 0D; + } + Object receiver = null; + long testIteration = 0; + for (long l = Long.MIN_VALUE;; l += STEP) { + double d = Double.longBitsToDouble(l); + Result expect = executeExpected(method, receiver, d); + try { + testAgainstExpected(options, method, expect, EMPTY, receiver, d); + testIteration++; + } catch (AssertionError e) { + throw new AssertionError(String.format("%d: While testing %g [long: %d, hex: %x]", testIteration, d, l, l), e); + } + if (Long.MAX_VALUE - STEP < l) { + break; + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java index a8d3cbe1275..24015c63783 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java @@ -227,13 +227,15 @@ public class AArch64Call { masm.ensureUniquePC(); } - public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) { - int before = masm.position(); - // Address is fixed up later by c++ code. - masm.jmp(); - int after = masm.position(); - crb.recordDirectCall(before, after, target, null); - masm.ensureUniquePC(); + public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget) { + try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) { + int before = masm.position(); + masm.movNativeAddress(scratch.getRegister(), 0L); + masm.jmp(scratch.getRegister()); + int after = masm.position(); + crb.recordDirectCall(before, after, callTarget, null); + masm.ensureUniquePC(); + } } public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java new file mode 100644 index 00000000000..ac9ef6094e3 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.lir.amd64; + +import static jdk.vm.ci.amd64.AMD64.k7; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rcx; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.EnumSet; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AvxVectorLen; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; +import sun.misc.Unsafe; + +/** + * Emits code which compares two arrays lexicographically. If the CPU supports any vector + * instructions specialized code is emitted to leverage these instructions. + */ +@Opcode("ARRAY_COMPARE_TO") +public final class AMD64ArrayCompareToOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ArrayCompareToOp.class); + + private final JavaKind kind1; + private final JavaKind kind2; + private final int array1BaseOffset; + private final int array2BaseOffset; + + @Def({REG}) protected Value resultValue; + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Alive({REG}) protected Value length1Value; + @Alive({REG}) protected Value length2Value; + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + + @Temp({REG, ILLEGAL}) protected Value vectorTemp1; + + public AMD64ArrayCompareToOp(LIRGeneratorTool tool, JavaKind kind1, JavaKind kind2, Value result, Value array1, Value array2, Value length1, Value length2) { + super(TYPE); + this.kind1 = kind1; + this.kind2 = kind2; + + // Both offsets should be the same but better be safe than sorry. + Class array1Class = Array.newInstance(kind1.toJavaClass(), 0).getClass(); + Class array2Class = Array.newInstance(kind2.toJavaClass(), 0).getClass(); + this.array1BaseOffset = UNSAFE.arrayBaseOffset(array1Class); + this.array2BaseOffset = UNSAFE.arrayBaseOffset(array2Class); + + this.resultValue = result; + this.array1Value = array1; + this.array2Value = array2; + this.length1Value = length1; + this.length2Value = length2; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + + // We only need the vector temporaries if we generate SSE code. + if (supportsSSE42(tool.target())) { + this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + } else { + this.vectorTemp1 = Value.ILLEGAL; + } + } + + private static boolean supportsSSE42(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + return arch.getFeatures().contains(CPUFeature.SSE4_2); + } + + private static boolean supportsAVX2(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + return arch.getFeatures().contains(CPUFeature.AVX2); + } + + private static boolean supportsAVX512VLBW(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + EnumSet features = arch.getFeatures(); + return features.contains(CPUFeature.AVX512BW) && features.contains(CPUFeature.AVX512VL); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register result = asRegister(resultValue); + Register str1 = asRegister(temp1); + Register str2 = asRegister(temp2); + + // Load array base addresses. + masm.leaq(str1, new AMD64Address(asRegister(array1Value), array1BaseOffset)); + masm.leaq(str2, new AMD64Address(asRegister(array2Value), array2BaseOffset)); + Register cnt1 = asRegister(length1Value); + Register cnt2 = asRegister(length2Value); + + // Checkstyle: stop + Label LENGTH_DIFF_LABEL = new Label(); + Label POP_LABEL = new Label(); + Label DONE_LABEL = new Label(); + Label WHILE_HEAD_LABEL = new Label(); + Label COMPARE_WIDE_VECTORS_LOOP_FAILED = new Label(); // used only _LP64 && AVX3 + int stride, stride2; + int adr_stride = -1; + int adr_stride1 = -1; + int adr_stride2 = -1; + // Checkstyle: resume + int stride2x2 = 0x40; + AMD64Address.Scale scale = null; + AMD64Address.Scale scale1 = null; + AMD64Address.Scale scale2 = null; + + // if (ae != StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + stride2x2 = 0x20; + } + + // if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { + if (kind1 != kind2) { + masm.shrl(cnt2, 1); + } + // Compute the minimum of the string lengths and the + // difference of the string lengths (stack). + // Do the conditional move stuff + masm.movl(result, cnt1); + masm.subl(cnt1, cnt2); + masm.push(cnt1); + masm.cmovl(ConditionFlag.LessEqual, cnt2, result); // cnt2 = min(cnt1, cnt2) + + // Is the minimum length zero? + masm.testl(cnt2, cnt2); + masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL); + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + // Load first bytes + masm.movzbl(result, new AMD64Address(str1, 0)); // result = str1[0] + masm.movzbl(cnt1, new AMD64Address(str2, 0)); // cnt1 = str2[0] + // } else if (ae == StrIntrinsicNode::UU) { + } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) { + // Load first characters + masm.movzwl(result, new AMD64Address(str1, 0)); + masm.movzwl(cnt1, new AMD64Address(str2, 0)); + } else { + masm.movzbl(result, new AMD64Address(str1, 0)); + masm.movzwl(cnt1, new AMD64Address(str2, 0)); + } + masm.subl(result, cnt1); + masm.jcc(ConditionFlag.NotZero, POP_LABEL); + + // if (ae == StrIntrinsicNode::UU) { + if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) { + // Divide length by 2 to get number of chars + masm.shrl(cnt2, 1); + } + masm.cmpl(cnt2, 1); + masm.jcc(ConditionFlag.Equal, LENGTH_DIFF_LABEL); + + // Check if the strings start at the same location and setup scale and stride + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.cmpptr(str1, str2); + masm.jcc(ConditionFlag.Equal, LENGTH_DIFF_LABEL); + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + scale = AMD64Address.Scale.Times1; + stride = 16; + } else { + scale = AMD64Address.Scale.Times2; + stride = 8; + } + } else { + scale1 = AMD64Address.Scale.Times1; + scale2 = AMD64Address.Scale.Times2; + // scale not used + stride = 8; + } + + // if (UseAVX >= 2 && UseSSE42Intrinsics) { + if (supportsAVX2(crb.target) && supportsSSE42(crb.target)) { + Register vec1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE); + + // Checkstyle: stop + Label COMPARE_WIDE_VECTORS = new Label(); + Label VECTOR_NOT_EQUAL = new Label(); + Label COMPARE_WIDE_TAIL = new Label(); + Label COMPARE_SMALL_STR = new Label(); + Label COMPARE_WIDE_VECTORS_LOOP = new Label(); + Label COMPARE_16_CHARS = new Label(); + Label COMPARE_INDEX_CHAR = new Label(); + Label COMPARE_WIDE_VECTORS_LOOP_AVX2 = new Label(); + Label COMPARE_TAIL_LONG = new Label(); + Label COMPARE_WIDE_VECTORS_LOOP_AVX3 = new Label(); // used only _LP64 && AVX3 + // Checkstyle: resume + + int pcmpmask = 0x19; + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + pcmpmask &= ~0x01; + } + + // Setup to compare 16-chars (32-bytes) vectors, + // start from first character again because it has aligned address. + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + stride2 = 32; + } else { + stride2 = 16; + } + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + adr_stride = stride << scale.log2; + } else { + adr_stride1 = 8; // stride << scale1; + adr_stride2 = 16; // stride << scale2; + } + + assert result.equals(rax) && cnt2.equals(rdx) && cnt1.equals(rcx) : "pcmpestri"; + // rax and rdx are used by pcmpestri as elements counters + masm.movl(result, cnt2); + masm.andl(cnt2, ~(stride2 - 1)); // cnt2 holds the vector count + masm.jcc(ConditionFlag.Zero, COMPARE_TAIL_LONG); + + // fast path : compare first 2 8-char vectors. + masm.bind(COMPARE_16_CHARS); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.movdqu(vec1, new AMD64Address(str1, 0)); + } else { + masm.pmovzxbw(vec1, new AMD64Address(str1, 0)); + } + masm.pcmpestri(vec1, new AMD64Address(str2, 0), pcmpmask); + masm.jccb(ConditionFlag.Below, COMPARE_INDEX_CHAR); + + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.movdqu(vec1, new AMD64Address(str1, adr_stride)); + masm.pcmpestri(vec1, new AMD64Address(str2, adr_stride), pcmpmask); + } else { + masm.pmovzxbw(vec1, new AMD64Address(str1, adr_stride1)); + masm.pcmpestri(vec1, new AMD64Address(str2, adr_stride2), pcmpmask); + } + masm.jccb(ConditionFlag.AboveEqual, COMPARE_WIDE_VECTORS); + masm.addl(cnt1, stride); + + // Compare the characters at index in cnt1 + masm.bind(COMPARE_INDEX_CHAR); // cnt1 has the offset of the mismatching character + loadNextElements(masm, result, cnt2, str1, str2, scale, scale1, scale2, cnt1); + masm.subl(result, cnt2); + masm.jmp(POP_LABEL); + + // Setup the registers to start vector comparison loop + masm.bind(COMPARE_WIDE_VECTORS); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.leaq(str1, new AMD64Address(str1, result, scale)); + masm.leaq(str2, new AMD64Address(str2, result, scale)); + } else { + masm.leaq(str1, new AMD64Address(str1, result, scale1)); + masm.leaq(str2, new AMD64Address(str2, result, scale2)); + } + masm.subl(result, stride2); + masm.subl(cnt2, stride2); + masm.jcc(ConditionFlag.Zero, COMPARE_WIDE_TAIL); + masm.negq(result); + + // In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest) + masm.bind(COMPARE_WIDE_VECTORS_LOOP); + + // if (VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop + if (supportsAVX512VLBW(crb.target)) { + masm.cmpl(cnt2, stride2x2); + masm.jccb(ConditionFlag.Below, COMPARE_WIDE_VECTORS_LOOP_AVX2); + masm.testl(cnt2, stride2x2 - 1); // cnt2 holds the vector count + // means we cannot subtract by 0x40 + masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP_AVX2); + + masm.bind(COMPARE_WIDE_VECTORS_LOOP_AVX3); // the hottest loop + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.evmovdquq(vec1, new AMD64Address(str1, result, scale), AvxVectorLen.AVX_512bit); + // k7 == 11..11, if operands equal, otherwise k7 has some 0 + masm.evpcmpeqb(k7, vec1, new AMD64Address(str2, result, scale), AvxVectorLen.AVX_512bit); + } else { + masm.vpmovzxbw(vec1, new AMD64Address(str1, result, scale1), AvxVectorLen.AVX_512bit); + // k7 == 11..11, if operands equal, otherwise k7 has some 0 + masm.evpcmpeqb(k7, vec1, new AMD64Address(str2, result, scale2), AvxVectorLen.AVX_512bit); + } + masm.kortestql(k7, k7); + masm.jcc(ConditionFlag.AboveEqual, COMPARE_WIDE_VECTORS_LOOP_FAILED); // miscompare + masm.addq(result, stride2x2); // update since we already compared at this addr + masm.subl(cnt2, stride2x2); // and sub the size too + masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP_AVX3); + + masm.vpxor(vec1, vec1, vec1); + masm.jmpb(COMPARE_WIDE_TAIL); + } + + masm.bind(COMPARE_WIDE_VECTORS_LOOP_AVX2); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.vmovdqu(vec1, new AMD64Address(str1, result, scale)); + masm.vpxor(vec1, vec1, new AMD64Address(str2, result, scale)); + } else { + masm.vpmovzxbw(vec1, new AMD64Address(str1, result, scale1), AvxVectorLen.AVX_256bit); + masm.vpxor(vec1, vec1, new AMD64Address(str2, result, scale2)); + } + masm.vptest(vec1, vec1); + masm.jcc(ConditionFlag.NotZero, VECTOR_NOT_EQUAL); + masm.addq(result, stride2); + masm.subl(cnt2, stride2); + masm.jcc(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP); + // clean upper bits of YMM registers + masm.vpxor(vec1, vec1, vec1); + + // compare wide vectors tail + masm.bind(COMPARE_WIDE_TAIL); + masm.testq(result, result); + masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL); + + masm.movl(result, stride2); + masm.movl(cnt2, result); + masm.negq(result); + masm.jmp(COMPARE_WIDE_VECTORS_LOOP_AVX2); + + // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors. + masm.bind(VECTOR_NOT_EQUAL); + // clean upper bits of YMM registers + masm.vpxor(vec1, vec1, vec1); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.leaq(str1, new AMD64Address(str1, result, scale)); + masm.leaq(str2, new AMD64Address(str2, result, scale)); + } else { + masm.leaq(str1, new AMD64Address(str1, result, scale1)); + masm.leaq(str2, new AMD64Address(str2, result, scale2)); + } + masm.jmp(COMPARE_16_CHARS); + + // Compare tail chars, length between 1 to 15 chars + masm.bind(COMPARE_TAIL_LONG); + masm.movl(cnt2, result); + masm.cmpl(cnt2, stride); + masm.jcc(ConditionFlag.Less, COMPARE_SMALL_STR); + + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.movdqu(vec1, new AMD64Address(str1, 0)); + } else { + masm.pmovzxbw(vec1, new AMD64Address(str1, 0)); + } + masm.pcmpestri(vec1, new AMD64Address(str2, 0), pcmpmask); + masm.jcc(ConditionFlag.Below, COMPARE_INDEX_CHAR); + masm.subq(cnt2, stride); + masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.leaq(str1, new AMD64Address(str1, result, scale)); + masm.leaq(str2, new AMD64Address(str2, result, scale)); + } else { + masm.leaq(str1, new AMD64Address(str1, result, scale1)); + masm.leaq(str2, new AMD64Address(str2, result, scale2)); + } + masm.negq(cnt2); + masm.jmpb(WHILE_HEAD_LABEL); + + masm.bind(COMPARE_SMALL_STR); + } else if (supportsSSE42(crb.target)) { + Register vec1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE); + + // Checkstyle: stop + Label COMPARE_WIDE_VECTORS = new Label(); + Label VECTOR_NOT_EQUAL = new Label(); + Label COMPARE_TAIL = new Label(); + // Checkstyle: resume + int pcmpmask = 0x19; + // Setup to compare 8-char (16-byte) vectors, + // start from first character again because it has aligned address. + masm.movl(result, cnt2); + masm.andl(cnt2, ~(stride - 1)); // cnt2 holds the vector count + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + pcmpmask &= ~0x01; + } + masm.jcc(ConditionFlag.Zero, COMPARE_TAIL); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.leaq(str1, new AMD64Address(str1, result, scale)); + masm.leaq(str2, new AMD64Address(str2, result, scale)); + } else { + masm.leaq(str1, new AMD64Address(str1, result, scale1)); + masm.leaq(str2, new AMD64Address(str2, result, scale2)); + } + masm.negq(result); + + // pcmpestri + // inputs: + // vec1- substring + // rax - negative string length (elements count) + // mem - scanned string + // rdx - string length (elements count) + // pcmpmask - cmp mode: 11000 (string compare with negated result) + // + 00 (unsigned bytes) or + 01 (unsigned shorts) + // outputs: + // rcx - first mismatched element index + assert result.equals(rax) && cnt2.equals(rdx) && cnt1.equals(rcx) : "pcmpestri"; + + masm.bind(COMPARE_WIDE_VECTORS); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.movdqu(vec1, new AMD64Address(str1, result, scale)); + masm.pcmpestri(vec1, new AMD64Address(str2, result, scale), pcmpmask); + } else { + masm.pmovzxbw(vec1, new AMD64Address(str1, result, scale1)); + masm.pcmpestri(vec1, new AMD64Address(str2, result, scale2), pcmpmask); + } + // After pcmpestri cnt1(rcx) contains mismatched element index + + masm.jccb(ConditionFlag.Below, VECTOR_NOT_EQUAL); // CF==1 + masm.addq(result, stride); + masm.subq(cnt2, stride); + masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS); + + // compare wide vectors tail + masm.testq(result, result); + masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL); + + masm.movl(cnt2, stride); + masm.movl(result, stride); + masm.negq(result); + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.movdqu(vec1, new AMD64Address(str1, result, scale)); + masm.pcmpestri(vec1, new AMD64Address(str2, result, scale), pcmpmask); + } else { + masm.pmovzxbw(vec1, new AMD64Address(str1, result, scale1)); + masm.pcmpestri(vec1, new AMD64Address(str2, result, scale2), pcmpmask); + } + masm.jccb(ConditionFlag.AboveEqual, LENGTH_DIFF_LABEL); + + // Mismatched characters in the vectors + masm.bind(VECTOR_NOT_EQUAL); + masm.addq(cnt1, result); + loadNextElements(masm, result, cnt2, str1, str2, scale, scale1, scale2, cnt1); + masm.subl(result, cnt2); + masm.jmpb(POP_LABEL); + + masm.bind(COMPARE_TAIL); // limit is zero + masm.movl(cnt2, result); + // Fallthru to tail compare + } + + // Shift str2 and str1 to the end of the arrays, negate min + // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + if (kind1 == kind2) { + masm.leaq(str1, new AMD64Address(str1, cnt2, scale)); + masm.leaq(str2, new AMD64Address(str2, cnt2, scale)); + } else { + masm.leaq(str1, new AMD64Address(str1, cnt2, scale1)); + masm.leaq(str2, new AMD64Address(str2, cnt2, scale2)); + } + masm.decrementl(cnt2); // first character was compared already + masm.negq(cnt2); + + // Compare the rest of the elements + masm.bind(WHILE_HEAD_LABEL); + loadNextElements(masm, result, cnt1, str1, str2, scale, scale1, scale2, cnt2); + masm.subl(result, cnt1); + masm.jccb(ConditionFlag.NotZero, POP_LABEL); + masm.incrementq(cnt2, 1); + masm.jccb(ConditionFlag.NotZero, WHILE_HEAD_LABEL); + + // Strings are equal up to min length. Return the length difference. + masm.bind(LENGTH_DIFF_LABEL); + masm.pop(result); + // if (ae == StrIntrinsicNode::UU) { + if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) { + // Divide diff by 2 to get number of chars + masm.sarl(result, 1); + } + masm.jmpb(DONE_LABEL); + + // if (VM_Version::supports_avx512vlbw()) { + if (supportsAVX512VLBW(crb.target)) { + masm.bind(COMPARE_WIDE_VECTORS_LOOP_FAILED); + + masm.kmovql(cnt1, k7); + masm.notq(cnt1); + masm.bsfq(cnt2, cnt1); + // if (ae != StrIntrinsicNode::LL) { + if (kind1 != JavaKind.Byte && kind2 != JavaKind.Byte) { + // Divide diff by 2 to get number of chars + masm.sarl(cnt2, 1); + } + masm.addq(result, cnt2); + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + masm.movzbl(cnt1, new AMD64Address(str2, result, Scale.Times1)); + masm.movzbl(result, new AMD64Address(str1, result, Scale.Times1)); + } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) { + masm.movzwl(cnt1, new AMD64Address(str2, result, scale)); + masm.movzwl(result, new AMD64Address(str1, result, scale)); + } else { + masm.movzwl(cnt1, new AMD64Address(str2, result, scale2)); + masm.movzbl(result, new AMD64Address(str1, result, scale1)); + } + masm.subl(result, cnt1); + masm.jmpb(POP_LABEL); + } + + // Discard the stored length difference + masm.bind(POP_LABEL); + masm.pop(cnt1); + + // That's it + masm.bind(DONE_LABEL); + // if (ae == StrIntrinsicNode::UL) { + if (kind1 == JavaKind.Char && kind2 == JavaKind.Byte) { + masm.negl(result); + } + } + + private void loadNextElements(AMD64MacroAssembler masm, Register elem1, Register elem2, Register str1, Register str2, + AMD64Address.Scale scale, AMD64Address.Scale scale1, + AMD64Address.Scale scale2, Register index) { + // if (ae == StrIntrinsicNode::LL) { + if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) { + masm.movzbl(elem1, new AMD64Address(str1, index, scale, 0)); + masm.movzbl(elem2, new AMD64Address(str2, index, scale, 0)); + // } else if (ae == StrIntrinsicNode::UU) { + } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) { + masm.movzwl(elem1, new AMD64Address(str1, index, scale, 0)); + masm.movzwl(elem2, new AMD64Address(str2, index, scale, 0)); + } else { + masm.movzbl(elem1, new AMD64Address(str1, index, scale1, 0)); + masm.movzwl(elem2, new AMD64Address(str2, index, scale2, 0)); + } + } + + private static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LFenceOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LFenceOp.java new file mode 100644 index 00000000000..7ee1c0216e0 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LFenceOp.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, 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. + * + * 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.lir.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +@Opcode("LFENCE") +public final class AMD64LFenceOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64LFenceOp.class); + + public AMD64LFenceOp() { + super(TYPE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { + asm.lfence(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java index 18345adca9f..c30148e4747 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java @@ -22,6 +22,11 @@ */ package org.graalvm.compiler.lir.amd64; +import static java.lang.Double.doubleToRawLongBits; +import static java.lang.Float.floatToRawIntBits; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; @@ -33,21 +38,16 @@ import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static java.lang.Double.doubleToRawLongBits; -import static java.lang.Float.floatToRawIntBits; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isRegister; -import static jdk.vm.ci.code.ValueUtil.isStackSlot; import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.CompressEncoding; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.spi.LIRKindTool; import org.graalvm.compiler.core.common.type.DataPointerConstant; import org.graalvm.compiler.debug.GraalError; @@ -59,6 +59,7 @@ import org.graalvm.compiler.lir.StandardOp.NullCheck; import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64Kind; @@ -763,7 +764,7 @@ public class AMD64Move { @Def({REG, HINT}) private AllocatableValue result; @Use({REG, CONST}) private Value input; - @Alive({REG, ILLEGAL}) private AllocatableValue baseRegister; + @Alive({REG, ILLEGAL, UNINITIALIZED}) private AllocatableValue baseRegister; protected PointerCompressionOp(LIRInstructionClass type, AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { @@ -777,8 +778,8 @@ public class AMD64Move { this.lirKindTool = lirKindTool; } - protected boolean hasBase(CompilationResultBuilder crb) { - return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase(); + public static boolean hasBase(OptionValues options, CompressEncoding encoding) { + return GeneratePIC.getValue(options) || encoding.hasBase(); } public final Value getInput() { @@ -820,7 +821,7 @@ public class AMD64Move { move(lirKindTool.getObjectKind(), crb, masm); Register resReg = asRegister(getResult()); - if (hasBase(crb)) { + if (hasBase(crb.getOptions(), encoding)) { Register baseReg = getBaseRegister(); if (!nonNull) { masm.testq(resReg, resReg); @@ -852,15 +853,15 @@ public class AMD64Move { @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { move(lirKindTool.getNarrowOopKind(), crb, masm); + emitUncompressCode(masm, asRegister(getResult()), getShift(), hasBase(crb.getOptions(), encoding) ? getBaseRegister() : null, nonNull); + } - Register resReg = asRegister(getResult()); - int shift = getShift(); + public static void emitUncompressCode(AMD64MacroAssembler masm, Register resReg, int shift, Register baseReg, boolean nonNull) { if (shift != 0) { masm.shlq(resReg, shift); } - if (hasBase(crb)) { - Register baseReg = getBaseRegister(); + if (baseReg != null) { if (nonNull) { masm.addq(resReg, baseReg); return; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java index c4b734c4556..b03892563b1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java @@ -96,7 +96,11 @@ public class LIRInstructionClass extends LIRIntrospection { try { Field field = clazz.getDeclaredField("TYPE"); field.setAccessible(true); - return (LIRInstructionClass) field.get(null); + LIRInstructionClass result = (LIRInstructionClass) field.get(null); + if (result == null) { + throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName()); + } + return result; } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { throw new RuntimeException(e); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java index 18d13713904..cdd71d23ef2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java @@ -53,7 +53,11 @@ public final class GlobalLivenessInfo { public final int[] emptySet; public Builder(LIR lir) { - info = new GlobalLivenessInfo(lir); + this(lir.numVariables(), lir.getControlFlowGraph().getBlocks().length); + } + + public Builder(int numVariables, int numBlocks) { + info = new GlobalLivenessInfo(numVariables, numBlocks); emptySet = new int[0]; } @@ -97,10 +101,8 @@ public final class GlobalLivenessInfo { private final Value[][] blockToLocIn; private final Value[][] blockToLocOut; - private GlobalLivenessInfo(LIR lir) { - int numVariables = lir.numVariables(); + private GlobalLivenessInfo(int numVariables, int numBlocks) { variables = new Variable[numVariables]; - int numBlocks = lir.getControlFlowGraph().getBlocks().length; blockToVarIn = new int[numBlocks][]; blockToVarOut = new int[numBlocks][]; blockToLocIn = new Value[numBlocks][]; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAssertions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAssertions.java new file mode 100644 index 00000000000..535ae68becc --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAssertions.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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. + * + * 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.lir.alloc.trace; + +import org.graalvm.compiler.core.common.alloc.Trace; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; + +/** + * A collection of assertions that are assumed to hold in various places of the Trace Register + * Allocation framework. + * + * The main goal is to document pieces of code that rely on specific properties of traces. In case + * an assumption is no longer valid, this makes it easy (assumed they are used correctly) to find + * places that need changes. + */ +final class TraceAssertions { + + /** + * Asserts that variable indices are properly sorted. + */ + public static boolean liveSetsAreSorted(GlobalLivenessInfo livenessInfo, AbstractBlockBase block) { + return isSorted(livenessInfo.getBlockIn(block)) && isSorted(livenessInfo.getBlockOut(block)); + } + + private static boolean isSorted(int[] live) { + if (live.length == 0) { + return true; + } + int current = live[0]; + for (int i = 1; i < live.length; i++) { + int last = current; + current = live[i]; + if (current <= last) { + return false; + } + } + return true; + } + + /** + * Asserts that a trace head has only a single predecessor. + * + * This is not true for every trace-building algorithm (for example + * {@link TraceBuilderPhase.TraceBuilder#SingleBlock}). + */ + public static boolean singleHeadPredecessor(Trace trace) { + return trace.getBlocks()[0].getPredecessorCount() == 1; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java index 64baae65575..988b98b334f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java @@ -84,32 +84,58 @@ public final class TraceGlobalMoveResolutionPhase { DebugContext debug = lir.getDebug(); try (Indent indent = debug.logAndIndent("Trace global move resolution")) { for (Trace trace : resultTraces.getTraces()) { - for (AbstractBlockBase fromBlock : trace.getBlocks()) { - for (AbstractBlockBase toBlock : fromBlock.getSuccessors()) { - if (resultTraces.getTraceForBlock(fromBlock) != resultTraces.getTraceForBlock(toBlock)) { - try (Indent indent0 = debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock, - resultTraces.getTraceForBlock(toBlock).getId())) { + resolveTrace(resultTraces, livenessInfo, lir, moveResolver, trace); + } + } + } - final ArrayList instructions; - final int insertIdx; - if (fromBlock.getSuccessorCount() == 1) { - instructions = lir.getLIRforBlock(fromBlock); - insertIdx = instructions.size() - 1; - } else { - assert toBlock.getPredecessorCount() == 1; - instructions = lir.getLIRforBlock(toBlock); - insertIdx = 1; - } - - moveResolver.setInsertPosition(instructions, insertIdx); - resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock); - moveResolver.resolveAndAppendMoves(); - } - } + private static void resolveTrace(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, Trace trace) { + AbstractBlockBase[] traceBlocks = trace.getBlocks(); + int traceLength = traceBlocks.length; + // all but the last block + AbstractBlockBase nextBlock = traceBlocks[0]; + for (int i = 1; i < traceLength; i++) { + AbstractBlockBase fromBlock = nextBlock; + nextBlock = traceBlocks[i]; + if (fromBlock.getSuccessorCount() > 1) { + for (AbstractBlockBase toBlock : fromBlock.getSuccessors()) { + if (toBlock != nextBlock) { + interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, fromBlock, toBlock); } } } } + // last block + assert nextBlock == traceBlocks[traceLength - 1]; + for (AbstractBlockBase toBlock : nextBlock.getSuccessors()) { + if (resultTraces.getTraceForBlock(nextBlock) != resultTraces.getTraceForBlock(toBlock)) { + interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, nextBlock, toBlock); + } + } + } + + @SuppressWarnings("try") + private static void interTraceEdge(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, AbstractBlockBase fromBlock, + AbstractBlockBase toBlock) { + DebugContext debug = lir.getDebug(); + try (Indent indent0 = debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock, + resultTraces.getTraceForBlock(toBlock).getId())) { + + final ArrayList instructions; + final int insertIdx; + if (fromBlock.getSuccessorCount() == 1) { + instructions = lir.getLIRforBlock(fromBlock); + insertIdx = instructions.size() - 1; + } else { + assert toBlock.getPredecessorCount() == 1; + instructions = lir.getLIRforBlock(toBlock); + insertIdx = 1; + } + + moveResolver.setInsertPosition(instructions, insertIdx); + resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock); + moveResolver.resolveAndAppendMoves(); + } } private static void resolveEdge(LIR lir, GlobalLivenessInfo livenessInfo, TraceGlobalMoveResolver moveResolver, AbstractBlockBase fromBlock, AbstractBlockBase toBlock) { @@ -129,6 +155,10 @@ public final class TraceGlobalMoveResolutionPhase { // GLI Value[] locFrom = livenessInfo.getOutLocation(fromBlock); Value[] locTo = livenessInfo.getInLocation(toBlock); + if (locFrom == locTo) { + // a strategy might reuse the locations array if locations are the same + return; + } assert locFrom.length == locTo.length; for (int i = 0; i < locFrom.length; i++) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java index 199adfe9220..ed6c54e788d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java @@ -36,19 +36,6 @@ import jdk.vm.ci.meta.Value; public class TraceUtil { - public static AbstractBlockBase getBestTraceInterPredecessor(TraceBuilderResult traceResult, AbstractBlockBase block) { - AbstractBlockBase bestPred = null; - int bestTraceId = traceResult.getTraceForBlock(block).getId(); - for (AbstractBlockBase pred : block.getPredecessors()) { - int predTraceId = traceResult.getTraceForBlock(pred).getId(); - if (predTraceId < bestTraceId) { - bestPred = pred; - bestTraceId = predTraceId; - } - } - return bestPred; - } - public static boolean isShadowedRegisterValue(Value value) { assert value != null; return value instanceof ShadowedRegisterValue; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java index 2912e1d8096..e3fc6f95fd1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -26,12 +26,13 @@ import static org.graalvm.compiler.lir.LIRValueUtil.asVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace; +import java.util.Arrays; import java.util.EnumSet; import org.graalvm.compiler.core.common.alloc.Trace; -import org.graalvm.compiler.core.common.alloc.TraceBuilderResult; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; import org.graalvm.compiler.lir.LIRInstruction.OperandMode; import org.graalvm.compiler.lir.StandardOp.JumpOp; @@ -47,68 +48,67 @@ import jdk.vm.ci.meta.Value; * Allocates a trivial trace i.e. a trace consisting of a single block with no instructions other * than the {@link LabelOp} and the {@link JumpOp}. */ -final class TrivialTraceAllocator extends TraceAllocationPhase { +public final class TrivialTraceAllocator extends TraceAllocationPhase { @Override protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) { LIR lir = lirGenRes.getLIR(); - TraceBuilderResult resultTraces = context.resultTraces; assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace; AbstractBlockBase block = trace.getBlocks()[0]; + assert TraceAssertions.singleHeadPredecessor(trace) : "Trace head with more than one predecessor?!" + trace; + AbstractBlockBase pred = block.getPredecessors()[0]; - AbstractBlockBase pred = TraceUtil.getBestTraceInterPredecessor(resultTraces, block); - - Value[] variableMap = new Value[lir.numVariables()]; GlobalLivenessInfo livenessInfo = context.livenessInfo; - collectMapping(block, pred, livenessInfo, variableMap); - assignLocations(lir, block, livenessInfo, variableMap); + allocate(block, pred, livenessInfo, SSAUtil.phiOutOrNull(lir, block)); } - /** - * Collects the mapping from variable to location. Additionally the - * {@link GlobalLivenessInfo#setInLocations incoming location array} is set. - */ - private static void collectMapping(AbstractBlockBase block, AbstractBlockBase pred, GlobalLivenessInfo livenessInfo, Value[] variableMap) { + public static void allocate(AbstractBlockBase block, AbstractBlockBase pred, GlobalLivenessInfo livenessInfo, LIRInstruction jump) { + // exploit that the live sets are sorted + assert TraceAssertions.liveSetsAreSorted(livenessInfo, block); + assert TraceAssertions.liveSetsAreSorted(livenessInfo, pred); + + // setup incoming variables/locations final int[] blockIn = livenessInfo.getBlockIn(block); final Value[] predLocOut = livenessInfo.getOutLocation(pred); - final Value[] locationIn = new Value[blockIn.length]; - for (int i = 0; i < blockIn.length; i++) { - int varNum = blockIn[i]; - if (varNum >= 0) { - Value location = predLocOut[i]; - variableMap[varNum] = location; - locationIn[i] = location; - } else { - locationIn[i] = Value.ILLEGAL; + int inLenght = blockIn.length; + + // setup outgoing variables/locations + final int[] blockOut = livenessInfo.getBlockOut(block); + int outLength = blockOut.length; + final Value[] locationOut = new Value[outLength]; + + assert outLength <= inLenght : "Trivial Trace! There cannot be more outgoing values than incoming."; + for (int outIdx = 0, inIdx = 0; outIdx < outLength; inIdx++) { + if (blockOut[outIdx] == blockIn[inIdx]) { + // set the outgoing location to the incoming value + locationOut[outIdx++] = predLocOut[inIdx]; } } - livenessInfo.setInLocations(block, locationIn); + + /* + * Since we do not change any of the location we can just use the outgoing of the + * predecessor. + */ + livenessInfo.setInLocations(block, predLocOut); + livenessInfo.setOutLocations(block, locationOut); + if (jump != null) { + handlePhiOut(jump, blockIn, predLocOut); + } } - /** - * Assigns the outgoing locations according to the {@link #collectMapping variable mapping}. - */ - private static void assignLocations(LIR lir, AbstractBlockBase block, GlobalLivenessInfo livenessInfo, Value[] variableMap) { - final int[] blockOut = livenessInfo.getBlockOut(block); - final Value[] locationOut = new Value[blockOut.length]; - for (int i = 0; i < blockOut.length; i++) { - int varNum = blockOut[i]; - locationOut[i] = variableMap[varNum]; - } - livenessInfo.setOutLocations(block, locationOut); - + private static void handlePhiOut(LIRInstruction jump, int[] varIn, Value[] locIn) { // handle outgoing phi values ValueProcedure outputConsumer = new ValueProcedure() { @Override public Value doValue(Value value, OperandMode mode, EnumSet flags) { if (isVariable(value)) { - return variableMap[asVariable(value).index]; + // since incoming variables are sorted, we can do a binary search + return locIn[Arrays.binarySearch(varIn, asVariable(value).index)]; } return value; } }; - JumpOp jump = SSAUtil.phiOut(lir, block); // Jumps have only alive values (outgoing phi values) jump.forEachAlive(outputConsumer); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java index 912e0f99cd3..bc4ece18d5f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java @@ -501,11 +501,12 @@ public final class BottomUpAllocator extends TraceAllocationPhase= 0; currentInstructionIndex--) { + final int lastInstIdx = currentInstructions.size() - 1; + for (currentInstructionIndex = lastInstIdx; currentInstructionIndex >= 0; currentInstructionIndex--) { LIRInstruction inst = currentInstructions.get(currentInstructionIndex); if (inst != null) { inst.setId(currentOpId); - allocateInstruction(inst, block); + allocateInstruction(inst, block, currentInstructionIndex == 0, currentInstructionIndex == lastInstIdx); } } allocatedBlocks.set(block.getId()); @@ -514,7 +515,7 @@ public final class BottomUpAllocator extends TraceAllocationPhase block) { + private void allocateInstruction(LIRInstruction op, AbstractBlockBase block, boolean isLabel, boolean isBlockEnd) { assert op != null && op.id() == currentOpId; try (Indent indent = debug.logAndIndent("handle inst: %d: %s", op.id(), op)) { try (Indent indent1 = debug.logAndIndent("output pos")) { @@ -537,7 +538,8 @@ public final class BottomUpAllocator extends TraceAllocationPhase currentBlock, AbstractBlockBase other) { - return traceBuilderResult.getTraceForBlock(other).getId() < traceBuilderResult.getTraceForBlock(currentBlock).getId(); - } - /** * Count instructions in all blocks. The numbering follows the * {@linkplain TraceLinearScan#sortedBlocks() register allocation order}. @@ -621,26 +617,29 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA assert allocator.instructionForId(opId) == op : "must match"; } + /** + * Add register hints for incoming values, i.e., values that are not defined in the trace. + * + * Due to the dominance property of SSA form, all values live at some point in the trace + * that are not defined in the trace are live at the beginning of it. + */ @SuppressWarnings("try") private void addInterTraceHints() { try (DebugContext.Scope s = debug.scope("InterTraceHints", allocator)) { - GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo(); - // set hints for phi/incoming intervals - for (AbstractBlockBase block : sortedBlocks()) { - LabelOp label = (LabelOp) getLIR().getLIRforBlock(block).get(0); - for (AbstractBlockBase pred : block.getPredecessors()) { - addInterTraceHints(livenessInfo, pred, block, label); - } + AbstractBlockBase traceHeadBlock = sortedBlocks()[0]; + if (traceHeadBlock.getPredecessorCount() == 0) { + return; } - } catch (Throwable e) { - throw debug.handle(e); - } - } + assert traceHeadBlock.getPredecessorCount() == 1 : "Trace head with more than one predecessor?!" + traceHeadBlock; - private void addInterTraceHints(GlobalLivenessInfo livenessInfo, AbstractBlockBase from, AbstractBlockBase to, LabelOp label) { - if (isAllocated(to, from)) { - int[] liveVars = livenessInfo.getBlockIn(to); - Value[] outLocation = livenessInfo.getOutLocation(from); + AbstractBlockBase pred = traceHeadBlock.getPredecessors()[0]; + assert traceBuilderResult.getTraceForBlock(pred).getId() < traceBuilderResult.getTraceForBlock(traceHeadBlock).getId() : "Not yet allocated? " + pred; + + GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo(); + LabelOp label = (LabelOp) getLIR().getLIRforBlock(traceHeadBlock).get(0); + + int[] liveVars = livenessInfo.getBlockIn(traceHeadBlock); + Value[] outLocation = livenessInfo.getOutLocation(pred); for (int i = 0; i < liveVars.length; i++) { int varNum = liveVars[i]; @@ -652,18 +651,20 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA } } } + } catch (Throwable e) { + throw debug.handle(e); } } private void addInterTraceHint(LabelOp label, int varNum, Value fromValue) { - assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue; + assert isRegister(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue; TraceInterval to = allocator.intervalFor(varNum); if (to == null) { // variable not live -> do nothing return; } - if (isVariableOrRegister(fromValue)) { - IntervalHint from = getIntervalHint((AllocatableValue) fromValue); + if (isRegister(fromValue)) { + IntervalHint from = allocator.getOrCreateFixedInterval(asRegisterValue(fromValue)); setHint(label, to, from, debug); } else if (isStackSlotValue(fromValue)) { setSpillSlot(label, to, (AllocatableValue) fromValue, debug); @@ -672,8 +673,6 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister()); setHint(label, to, from, debug); setSpillSlot(label, to, shadowedRegisterValue.getStackSlot(), debug); - } else { - throw GraalError.shouldNotReachHere(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java index c82c7e7ec33..51d4bf49434 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java @@ -252,11 +252,16 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF Variable emitByteSwap(Value operand); + @SuppressWarnings("unused") + default Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) { + throw GraalError.unimplemented("String.compareTo substitution is not implemented on this architecture"); + } + Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length); @SuppressWarnings("unused") default Variable emitStringIndexOf(Value sourcePointer, Value sourceCount, Value targetPointer, Value targetCount, int constantTargetCount) { - throw GraalError.unimplemented(); + throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture"); } void emitBlackhole(Value operand); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java index 0bb2d992999..c9850c91c3c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java @@ -39,6 +39,13 @@ public class LIRPhaseSuite extends LIRPhase { phases = new ArrayList<>(); } + /** + * Gets an unmodifiable view on the phases in this suite. + */ + public List> getPhases() { + return Collections.unmodifiableList(phases); + } + /** * Add a new phase at the beginning of this suite. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java index 5f866d350d0..0e1a9a64d4f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java @@ -112,6 +112,13 @@ public final class SSAUtil { return (JumpOp) op; } + public static JumpOp phiOutOrNull(LIR lir, AbstractBlockBase block) { + if (block.getSuccessorCount() != 1) { + return null; + } + return phiOut(lir, block); + } + public static int phiOutIndex(LIR lir, AbstractBlockBase block) { assert block.getSuccessorCount() == 1; ArrayList instructions = lir.getLIRforBlock(block); @@ -181,4 +188,19 @@ public final class SSAUtil { return -1; } + public static int numPhiOut(LIR lir, AbstractBlockBase block) { + if (block.getSuccessorCount() != 1) { + // cannot be a phi_out block + return 0; + } + return numPhiIn(lir, block.getSuccessors()[0]); + } + + private static int numPhiIn(LIR lir, AbstractBlockBase block) { + if (!isMerge(block)) { + return 0; + } + return phiIn(lir, block).getPhiSize(); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java index 5c2683200e9..9e9c2a445a2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java @@ -28,6 +28,7 @@ import static org.graalvm.compiler.loop.MathUtil.sub; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.util.UnsignedLong; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; @@ -159,7 +160,7 @@ public class BasicInductionVariable extends InductionVariable { @Override public ValueNode exitValueNode() { Stamp stamp = phi.stamp(NodeView.DEFAULT); - ValueNode maxTripCount = loop.counted().maxTripCountNode(false); + ValueNode maxTripCount = loop.counted().maxTripCountNode(); if (!maxTripCount.stamp(NodeView.DEFAULT).isCompatible(stamp)) { maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph(), NodeView.DEFAULT); } @@ -173,7 +174,11 @@ public class BasicInductionVariable extends InductionVariable { @Override public long constantExtremum() { - return constantStride() * (loop.counted().constantMaxTripCount() - 1) + constantInit(); + UnsignedLong tripCount = loop.counted().constantMaxTripCount(); + if (tripCount.isLessThan(1)) { + return constantInit(); + } + return tripCount.minus(1).wrappingTimes(constantStride()).wrappingPlus(constantInit()).asLong(); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java index 510db102ab9..f1200f89532 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java @@ -23,11 +23,12 @@ package org.graalvm.compiler.loop; import static org.graalvm.compiler.loop.MathUtil.add; -import static org.graalvm.compiler.loop.MathUtil.divBefore; import static org.graalvm.compiler.loop.MathUtil.sub; +import static org.graalvm.compiler.loop.MathUtil.unsignedDivBefore; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.util.UnsignedLong; import org.graalvm.compiler.loop.InductionVariable.Direction; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.ConstantNode; @@ -39,6 +40,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.CompareNode; import org.graalvm.compiler.nodes.calc.ConditionalNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; +import org.graalvm.compiler.nodes.calc.NegateNode; import org.graalvm.compiler.nodes.extended.GuardingNode; import jdk.vm.ci.code.CodeUtil; @@ -64,38 +66,58 @@ public class CountedLoopInfo { this.ifNode = ifNode; } + /** + * Returns a node that computes the maximum trip count of this loop. That is the trip count of + * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest() + * count check}. + * + * This count is exact if {@link #isExactTripCount()} returns true. + * + * THIS VALUE SHOULD BE TREATED AS UNSIGNED. + */ public ValueNode maxTripCountNode() { return maxTripCountNode(false); } + /** + * Returns a node that computes the maximum trip count of this loop. That is the trip count of + * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest() + * count check}. + * + * This count is exact if {@link #isExactTripCount()} returns true. + * + * THIS VALUE SHOULD BE TREATED AS UNSIGNED. + * + * @param assumePositive if true the check that the loop is entered at all will be omitted. + */ public ValueNode maxTripCountNode(boolean assumePositive) { StructuredGraph graph = iv.valueNode().graph(); Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT); - ValueNode range = sub(graph, end, iv.initNode()); ValueNode max; ValueNode min; - ValueNode oneDirection; + ValueNode range; + ValueNode absStride; if (iv.direction() == Direction.Up) { - oneDirection = ConstantNode.forIntegerStamp(stamp, 1, graph); + absStride = iv.strideNode(); + range = sub(graph, end, iv.initNode()); max = end; min = iv.initNode(); } else { assert iv.direction() == Direction.Down; - oneDirection = ConstantNode.forIntegerStamp(stamp, -1, graph); + absStride = graph.maybeAddOrUnique(NegateNode.create(iv.strideNode(), NodeView.DEFAULT)); + range = sub(graph, iv.initNode(), end); max = iv.initNode(); min = end; } + + ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph); if (oneOff) { - range = add(graph, range, oneDirection); + range = add(graph, range, one); } // round-away-from-zero divison: (range + stride -/+ 1) / stride - ValueNode denominator = range; - if (!oneDirection.stamp(NodeView.DEFAULT).equals(iv.strideNode().stamp(NodeView.DEFAULT))) { - ValueNode subedRanged = sub(graph, range, oneDirection); - denominator = add(graph, subedRanged, iv.strideNode()); - } - ValueNode div = divBefore(graph, loop.entryPoint(), denominator, iv.strideNode()); + ValueNode denominator = add(graph, range, sub(graph, absStride, one)); + ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride); if (assumePositive) { return div; @@ -105,49 +127,44 @@ public class CountedLoopInfo { } /** - * @return true if the loop has constant bounds and the trip count is representable as a - * positive integer. + * @return true if the loop has constant bounds. */ public boolean isConstantMaxTripCount() { - /* - * It's possible that the iteration range is too large to treat this as constant because it - * will overflow. - */ - return (hasConstantBounds() && rawConstantMaxTripCount() >= 0); - } - - /** - * @return true if the bounds on the iteration space are all constants. - */ - public boolean hasConstantBounds() { return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride(); } - public long constantMaxTripCount() { + public UnsignedLong constantMaxTripCount() { assert isConstantMaxTripCount(); - return rawConstantMaxTripCount(); + return new UnsignedLong(rawConstantMaxTripCount()); } /** - * Compute the raw value of the trip count for this loop. Since we don't have unsigned values - * this may be outside representable positive values. + * Compute the raw value of the trip count for this loop. THIS IS AN UNSIGNED VALUE; */ - protected long rawConstantMaxTripCount() { + private long rawConstantMaxTripCount() { assert iv.direction() != null; - long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0; - long endValue = ((ConstantNode) end).asJavaConstant().asLong(); - try { - // If no overflow occurs then negative values represent a trip count of 0 - long max = Math.subtractExact(Math.addExact(endValue, off), iv.constantInit()) / iv.constantStride(); - return Math.max(0, max); - } catch (ArithmeticException e) { - /* - * The computation overflowed to return a negative value. It's possible some - * optimization could handle this value as an unsigned and produce the right answer but - * we hide this value by default. - */ - return -1; + long endValue = end.asJavaConstant().asLong(); + long initValue = iv.constantInit(); + long range; + long absStride; + if (iv.direction() == Direction.Up) { + if (endValue < initValue) { + return 0; + } + range = endValue - iv.constantInit(); + absStride = iv.constantStride(); + } else { + if (initValue < endValue) { + return 0; + } + range = iv.constantInit() - endValue; + absStride = -iv.constantStride(); } + if (oneOff) { + range += 1; + } + long denominator = range + absStride - 1; + return Long.divideUnsigned(denominator, absStride); } public boolean isExactTripCount() { @@ -164,7 +181,7 @@ public class CountedLoopInfo { return isConstantMaxTripCount(); } - public long constantExactTripCount() { + public UnsignedLong constantExactTripCount() { assert isExactTripCount(); return constantMaxTripCount(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java index ada82be03ef..65f83eba1f7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java @@ -28,6 +28,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.MinimumPeelProbabili import java.util.List; +import org.graalvm.compiler.core.common.util.UnsignedLong; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; @@ -89,11 +90,22 @@ public class DefaultLoopPolicies implements LoopPolicies { } OptionValues options = loop.entryPoint().getOptions(); CountedLoopInfo counted = loop.counted(); - long maxTrips = counted.constantMaxTripCount(); + UnsignedLong maxTrips = counted.constantMaxTripCount(); + if (maxTrips.equals(0)) { + return loop.canDuplicateLoop(); + } int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? Options.ExactFullUnrollMaxNodes.getValue(options) : Options.FullUnrollMaxNodes.getValue(options); maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue(options) - loop.loopBegin().graph().getNodeCount())); int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); - if (maxTrips <= Options.FullUnrollMaxIterations.getValue(options) && size * (maxTrips - 1) <= maxNodes) { + /* @formatter:off + * The check below should not throw ArithmeticException because: + * maxTrips is guaranteed to be >= 1 by the check above + * - maxTrips * size can not overfow because: + * - maxTrips <= FullUnrollMaxIterations <= Integer.MAX_VALUE + * - 1 <= size <= Integer.MAX_VALUE + * @formatter:on + */ + if (maxTrips.isLessOrEqualTo(Options.FullUnrollMaxIterations.getValue(options)) && maxTrips.minus(1).times(size).isLessOrEqualTo(maxNodes)) { // check whether we're allowed to unroll this loop return loop.canDuplicateLoop(); } else { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java index 6014cebf3f7..3485c3be0f5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java @@ -35,6 +35,7 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeBitMap; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.EndNode; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FrameState; @@ -208,6 +209,12 @@ public abstract class LoopFragment { NodeWithState withState = (NodeWithState) n; withState.states().forEach(state -> state.applyToVirtual(node -> nodes.mark(node))); } + if (n instanceof AbstractMergeNode) { + // if a merge is in the loop, all of its phis are also in the loop + for (PhiNode phi : ((AbstractMergeNode) n).phis()) { + nodes.mark(phi); + } + } nodes.mark(n); } } @@ -246,6 +253,17 @@ public abstract class LoopFragment { if (n instanceof MonitorEnterNode) { markFloating(worklist, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes); } + if (n instanceof AbstractMergeNode) { + /* + * Since we already marked all phi nodes as being in the loop to break cycles, + * we also have to iterate over their usages here. + */ + for (PhiNode phi : ((AbstractMergeNode) n).phis()) { + for (Node usage : phi.usages()) { + markFloating(worklist, usage, nodes, nonLoopNodes); + } + } + } for (Node usage : n.usages()) { markFloating(worklist, usage, nodes, nonLoopNodes); } @@ -263,6 +281,20 @@ public abstract class LoopFragment { this.usages = n.usages().iterator(); this.isLoopNode = loopNodes.isMarked(n); } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof WorkListEntry)) { + return false; + } + WorkListEntry other = (WorkListEntry) obj; + return this.n == other.n; + } + + @Override + public int hashCode() { + return n.hashCode(); + } } static TriState isLoopNode(Node n, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) { @@ -272,32 +304,24 @@ public abstract class LoopFragment { if (nonLoopNodes.isMarked(n)) { return TriState.FALSE; } - if (n instanceof FixedNode) { + if (n instanceof FixedNode || n instanceof PhiNode) { + // phi nodes are treated the same as fixed nodes in this algorithm to break cycles return TriState.FALSE; } - boolean mark = false; - if (n instanceof PhiNode) { - PhiNode phi = (PhiNode) n; - mark = loopNodes.isMarked(phi.merge()); - if (mark) { - /* - * This Phi is a loop node but the inputs might not be so they must be processed by - * the caller. - */ - loopNodes.mark(n); - } else { - nonLoopNodes.mark(n); - return TriState.FALSE; - } - } return TriState.UNKNOWN; } + private static void pushWorkList(Deque workList, Node node, NodeBitMap loopNodes) { + WorkListEntry entry = new WorkListEntry(node, loopNodes); + assert !workList.contains(entry) : "node " + node + " added to worklist twice"; + workList.push(entry); + } + private static void markFloating(Deque workList, Node start, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) { if (isLoopNode(start, loopNodes, nonLoopNodes).isKnown()) { return; } - workList.push(new WorkListEntry(start, loopNodes)); + pushWorkList(workList, start, loopNodes); while (!workList.isEmpty()) { WorkListEntry currentEntry = workList.peek(); if (currentEntry.usages.hasNext()) { @@ -308,7 +332,7 @@ public abstract class LoopFragment { currentEntry.isLoopNode = true; } } else { - workList.push(new WorkListEntry(current, loopNodes)); + pushWorkList(workList, current, loopNodes); } } else { workList.pop(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java index 42b656da7b3..989a5fa7c52 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java @@ -28,6 +28,7 @@ import java.util.List; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; @@ -338,6 +339,7 @@ public class LoopFragmentInside extends LoopFragment { } @Override + @SuppressWarnings("try") protected DuplicationReplacement getDuplicationReplacement() { final LoopBeginNode loopBegin = loop().loopBegin(); final StructuredGraph graph = graph(); @@ -347,34 +349,36 @@ public class LoopFragmentInside extends LoopFragment { @Override public Node replacement(Node original) { - if (original == loopBegin) { - Node value = seenNode.get(original); - if (value != null) { - return value; + try (DebugCloseable position = original.withNodeSourcePosition()) { + if (original == loopBegin) { + Node value = seenNode.get(original); + if (value != null) { + return value; + } + AbstractBeginNode newValue = graph.add(new BeginNode()); + seenNode.put(original, newValue); + return newValue; } - AbstractBeginNode newValue = graph.add(new BeginNode()); - seenNode.put(original, newValue); - return newValue; - } - if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) { - Node value = seenNode.get(original); - if (value != null) { - return value; + if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) { + Node value = seenNode.get(original); + if (value != null) { + return value; + } + AbstractBeginNode newValue = graph.add(new BeginNode()); + seenNode.put(original, newValue); + return newValue; } - AbstractBeginNode newValue = graph.add(new BeginNode()); - seenNode.put(original, newValue); - return newValue; - } - if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) { - Node value = seenNode.get(original); - if (value != null) { - return value; + if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) { + Node value = seenNode.get(original); + if (value != null) { + return value; + } + EndNode newValue = graph.add(new EndNode()); + seenNode.put(original, newValue); + return newValue; } - EndNode newValue = graph.add(new EndNode()); - seenNode.put(original, newValue); - return newValue; + return original; } - return original; } }; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java index 6a20d17faae..5d603eae10b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java @@ -30,6 +30,9 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; import org.graalvm.compiler.nodes.calc.FixedBinaryNode; import org.graalvm.compiler.nodes.calc.SignedDivNode; +import org.graalvm.compiler.nodes.calc.UnsignedDivNode; + +import java.util.function.BiFunction; /** * Utility methods to perform integer math with some obvious constant folding first. @@ -71,12 +74,28 @@ public class MathUtil { } public static ValueNode divBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) { + return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> SignedDivNode.create(dend, sor, NodeView.DEFAULT)); + } + + public static ValueNode unsignedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) { + return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> UnsignedDivNode.create(dend, sor, NodeView.DEFAULT)); + } + + private static ValueNode fixedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor, BiFunction createDiv) { if (isConstantOne(divisor)) { return dividend; } - ValueNode div = graph.addOrUniqueWithInputs(SignedDivNode.create(dividend, divisor, NodeView.DEFAULT)); + ValueNode div = graph.addOrUniqueWithInputs(createDiv.apply(dividend, divisor)); if (div instanceof FixedBinaryNode) { - graph.addBeforeFixed(before, (FixedBinaryNode) div); + FixedBinaryNode fixedDiv = (FixedBinaryNode) div; + if (before.predecessor() instanceof FixedBinaryNode) { + FixedBinaryNode binaryPredecessor = (FixedBinaryNode) before.predecessor(); + if (fixedDiv.dataFlowEquals(binaryPredecessor)) { + fixedDiv.safeDelete(); + return binaryPredecessor; + } + } + graph.addBeforeFixed(before, fixedDiv); } return div; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java index 756661318ff..4ebbdfc9065 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java @@ -570,4 +570,16 @@ public class IntegerStampTest extends GraphTest { assertEquals(IntegerStamp.create(bits, 0, 1000), div.foldStamp(IntegerStamp.create(bits, 100, 1000), IntegerStamp.create(bits, 1, max))); assertEquals(IntegerStamp.create(bits, -1000, 0), div.foldStamp(IntegerStamp.create(bits, -1000, -100), IntegerStamp.create(bits, 1, max))); } + + @Test + public void testEmpty() { + IntegerStamp intStamp = StampFactory.forInteger(32); + IntegerStamp longStamp = StampFactory.forInteger(64); + Stamp intEmpty = StampFactory.empty(JavaKind.Int); + Stamp longEmpty = StampFactory.empty(JavaKind.Long); + assertEquals(intStamp.join(intEmpty), intEmpty); + assertEquals(intStamp.meet(intEmpty), intStamp); + assertEquals(longStamp.join(longEmpty), longEmpty); + assertEquals(longStamp.meet(longEmpty), longStamp); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java index c8ed8a5816d..27df7159259 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java @@ -35,6 +35,7 @@ import org.graalvm.compiler.core.common.type.FloatStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.PrimitiveStamp; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.test.GraalTest; import org.junit.Test; @@ -64,6 +65,7 @@ public class PrimitiveStampBoundaryTest extends GraalTest { shiftStamps.add(IntegerStamp.create(32, Math.min(v1, v2), Math.max(v1, v2))); } } + shiftStamps.add((IntegerStamp) StampFactory.empty(JavaKind.Int)); integerTestStamps = new HashSet<>(); for (long v1 : longBoundaryValues) { @@ -74,6 +76,8 @@ public class PrimitiveStampBoundaryTest extends GraalTest { integerTestStamps.add(IntegerStamp.create(64, Math.min(v1, v2), Math.max(v1, v2))); } } + integerTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Int)); + integerTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Long)); } static double[] doubleBoundaryValues = {Double.NEGATIVE_INFINITY, Double.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.MIN_VALUE, @@ -98,6 +102,8 @@ public class PrimitiveStampBoundaryTest extends GraalTest { generateFloatingStamps(new FloatStamp(64, Math.min(d1, d2), Math.max(d1, d2), false)); } } + floatTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Float)); + floatTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Double)); } private static void generateFloatingStamps(FloatStamp floatStamp) { @@ -130,7 +136,7 @@ public class PrimitiveStampBoundaryTest extends GraalTest { private static void checkConvertOperation(IntegerConvertOp op, int inputBits, int resultBits, Stamp result, Stamp v1stamp) { Stamp folded = op.foldStamp(inputBits, resultBits, v1stamp); - assertTrue(folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded); + assertTrue(folded.isEmpty() || folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded); assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded)); } @@ -167,7 +173,7 @@ public class PrimitiveStampBoundaryTest extends GraalTest { private static void checkConvertOperation(ArithmeticOpTable.FloatConvertOp op, Stamp result, Stamp v1stamp) { Stamp folded = op.foldStamp(v1stamp); - assertTrue(folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded); + assertTrue(folded.isEmpty() || folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded); assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded)); } @@ -184,6 +190,10 @@ public class PrimitiveStampBoundaryTest extends GraalTest { IntegerStamp stamp = (IntegerStamp) testStamp; for (IntegerStamp shiftStamp : shifts) { IntegerStamp foldedStamp = (IntegerStamp) shiftOp.foldStamp(stamp, shiftStamp); + if (foldedStamp.isEmpty()) { + assertTrue(stamp.isEmpty() || shiftStamp.isEmpty()); + continue; + } checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.lowerBound(), shiftStamp.lowerBound()); checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.lowerBound(), shiftStamp.upperBound()); checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.upperBound(), shiftStamp.lowerBound()); @@ -205,8 +215,15 @@ public class PrimitiveStampBoundaryTest extends GraalTest { private static void checkBinaryOperation(ArithmeticOpTable.BinaryOp op, Stamp result, Stamp v1stamp, Stamp v2stamp) { Stamp folded = op.foldStamp(v1stamp, v2stamp); + if (v1stamp.isEmpty() || v2stamp.isEmpty()) { + assertTrue(folded.isEmpty()); + assertTrue(v1stamp.asConstant() != null || v1stamp.isEmpty()); + assertTrue(v2stamp.asConstant() != null || v2stamp.isEmpty()); + return; + } Constant constant = op.foldConstant(v1stamp.asConstant(), v2stamp.asConstant()); if (constant != null) { + assertFalse(folded.isEmpty()); Constant constant2 = folded.asConstant(); if (constant2 == null && v1stamp instanceof FloatStamp) { JavaConstant c = (JavaConstant) constant; @@ -239,6 +256,9 @@ public class PrimitiveStampBoundaryTest extends GraalTest { } private static Stamp boundaryStamp(Stamp v1, boolean upper) { + if (v1.isEmpty()) { + return v1; + } if (v1 instanceof IntegerStamp) { IntegerStamp istamp = (IntegerStamp) v1; long bound = upper ? istamp.upperBound() : istamp.lowerBound(); @@ -319,7 +339,7 @@ public class PrimitiveStampBoundaryTest extends GraalTest { } } } else { - assert v1stamp instanceof FloatStamp; + assertTrue(v1stamp.isEmpty() || v1stamp instanceof FloatStamp); } assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java index f6ff25e58a9..d4f984d04ea 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java @@ -23,6 +23,7 @@ package org.graalvm.compiler.nodes; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Simplifiable; import org.graalvm.compiler.graph.spi.SimplifierTool; @@ -41,8 +42,8 @@ public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNo public static final NodeClass TYPE = NodeClass.create(AbstractFixedGuardNode.class); @Input(InputType.Condition) protected LogicNode condition; - protected final DeoptimizationReason reason; - protected final DeoptimizationAction action; + protected DeoptimizationReason reason; + protected DeoptimizationAction action; protected JavaConstant speculation; protected boolean negated; @@ -109,29 +110,42 @@ public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNo } } + @SuppressWarnings("try") public DeoptimizeNode lowerToIf() { - FixedNode currentNext = next(); - setNext(null); - DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason, speculation)); - deopt.setStateBefore(stateBefore()); - IfNode ifNode; - AbstractBeginNode noDeoptSuccessor; - if (negated) { - ifNode = graph().add(new IfNode(condition, deopt, currentNext, 0)); - noDeoptSuccessor = ifNode.falseSuccessor(); - } else { - ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1)); - noDeoptSuccessor = ifNode.trueSuccessor(); - } - ((FixedWithNextNode) predecessor()).setNext(ifNode); - this.replaceAtUsages(noDeoptSuccessor); - GraphUtil.killWithUnusedFloatingInputs(this); + try (DebugCloseable position = this.withNodeSourcePosition()) { + FixedNode currentNext = next(); + setNext(null); + DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason, speculation)); + deopt.setStateBefore(stateBefore()); + IfNode ifNode; + AbstractBeginNode noDeoptSuccessor; + if (negated) { + ifNode = graph().add(new IfNode(condition, deopt, currentNext, 0)); + noDeoptSuccessor = ifNode.falseSuccessor(); + } else { + ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1)); + noDeoptSuccessor = ifNode.trueSuccessor(); + } + ((FixedWithNextNode) predecessor()).setNext(ifNode); + this.replaceAtUsages(noDeoptSuccessor); + GraphUtil.killWithUnusedFloatingInputs(this); - return deopt; + return deopt; + } } @Override public boolean canDeoptimize() { return true; } + + @Override + public void setAction(DeoptimizationAction action) { + this.action = action; + } + + @Override + public void setReason(DeoptimizationReason reason) { + this.reason = reason; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java index 1bf6617d851..2024c792aab 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java @@ -27,6 +27,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Simplifiable; import org.graalvm.compiler.graph.spi.SimplifierTool; @@ -71,12 +72,15 @@ public final class BeginNode extends AbstractBeginNode implements Simplifiable { } } + @SuppressWarnings("try") public static AbstractBeginNode begin(FixedNode with) { - if (with instanceof AbstractBeginNode) { - return (AbstractBeginNode) with; + try (DebugCloseable position = with.withNodeSourcePosition()) { + if (with instanceof AbstractBeginNode) { + return (AbstractBeginNode) with; + } + BeginNode begin = with.graph().add(new BeginNode()); + begin.setNext(with); + return begin; } - BeginNode begin = with.graph().add(new BeginNode()); - begin.setNext(with); - return begin; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java index 43b9a491b38..17e52eb3b06 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java @@ -43,8 +43,8 @@ public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowe public static final int DEFAULT_DEBUG_ID = 0; public static final NodeClass TYPE = NodeClass.create(DeoptimizeNode.class); - protected final DeoptimizationAction action; - protected final DeoptimizationReason reason; + protected DeoptimizationAction action; + protected DeoptimizationReason reason; protected int debugId; protected final JavaConstant speculation; @@ -72,11 +72,21 @@ public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowe return action; } + @Override + public void setAction(DeoptimizationAction action) { + this.action = action; + } + @Override public DeoptimizationReason getReason() { return reason; } + @Override + public void setReason(DeoptimizationReason reason) { + this.reason = reason; + } + @Override public void lower(LoweringTool tool) { tool.getLowerer().lower(this, tool); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java index 859375bb9b6..1e9950499b9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java @@ -31,6 +31,8 @@ import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.extended.GuardingNode; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -42,29 +44,55 @@ public final class DynamicPiNode extends PiNode { public static final NodeClass TYPE = NodeClass.create(DynamicPiNode.class); @Input ValueNode typeMirror; + private final boolean exact; - public DynamicPiNode(ValueNode object, GuardingNode guard, ValueNode typeMirror) { + protected DynamicPiNode(ValueNode object, GuardingNode guard, ValueNode typeMirror, boolean exact) { super(TYPE, object, StampFactory.object(), guard); this.typeMirror = typeMirror; + this.exact = exact; } - @Override - public Node canonical(CanonicalizerTool tool) { + public static ValueNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode object, GuardingNode guard, ValueNode typeMirror, boolean exact) { + ValueNode synonym = findSynonym(assumptions, constantReflection, object, guard, typeMirror, exact); + if (synonym != null) { + return synonym; + } + return new DynamicPiNode(object, guard, typeMirror, exact); + } + + public static ValueNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode object, GuardingNode guard, ValueNode typeMirror) { + return create(assumptions, constantReflection, object, guard, typeMirror, false); + } + + public boolean isExact() { + return exact; + } + + private static ValueNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode object, GuardingNode guard, ValueNode typeMirror, boolean exact) { if (typeMirror.isConstant()) { - ResolvedJavaType t = tool.getConstantReflection().asJavaType(typeMirror.asConstant()); + ResolvedJavaType t = constantReflection.asJavaType(typeMirror.asConstant()); if (t != null) { Stamp staticPiStamp; if (t.isPrimitive()) { staticPiStamp = StampFactory.alwaysNull(); } else { - TypeReference type = TypeReference.createTrusted(tool.getAssumptions(), t); + TypeReference type = exact ? TypeReference.createExactTrusted(t) : TypeReference.createTrusted(assumptions, t); staticPiStamp = StampFactory.object(type); } - return new PiNode(object(), staticPiStamp, (ValueNode) getGuard()).canonical(tool); + return PiNode.create(object, staticPiStamp, (ValueNode) guard); } } + return null; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ValueNode synonym = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), object, guard, typeMirror, exact); + if (synonym != null) { + return synonym; + } return this; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java index c9a53357e96..8fe812f285d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java @@ -24,9 +24,11 @@ package org.graalvm.compiler.nodes; import java.util.List; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.NodeClass; import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -34,7 +36,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; * {@link GraphEncoder} for a description of the encoding format. Use {@link GraphDecoder} for * decoding. */ -public class EncodedGraph { +public final class EncodedGraph { private final byte[] encoding; private final int startOffset; @@ -42,6 +44,9 @@ public class EncodedGraph { private final NodeClass[] types; private final Assumptions assumptions; private final List inlinedMethods; + private final boolean trackNodeSourcePosition; + private final EconomicSet fields; + private final boolean hasUnsafeAccess; /** * The "table of contents" of the encoded graph, i.e., the mapping from orderId numbers to the @@ -49,13 +54,22 @@ public class EncodedGraph { */ protected int[] nodeStartOffsets; - public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass[] types, Assumptions assumptions, List inlinedMethods) { + public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass[] types, StructuredGraph sourceGraph) { + this(encoding, startOffset, objects, types, sourceGraph.getAssumptions(), sourceGraph.getMethods(), sourceGraph.getFields(), sourceGraph.hasUnsafeAccess(), + sourceGraph.trackNodeSourcePosition()); + } + + public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass[] types, Assumptions assumptions, List inlinedMethods, + EconomicSet fields, boolean hasUnsafeAccess, boolean trackNodeSourcePosition) { this.encoding = encoding; this.startOffset = startOffset; this.objects = objects; this.types = types; this.assumptions = assumptions; this.inlinedMethods = inlinedMethods; + this.trackNodeSourcePosition = trackNodeSourcePosition; + this.fields = fields; + this.hasUnsafeAccess = hasUnsafeAccess; } public byte[] getEncoding() { @@ -81,4 +95,16 @@ public class EncodedGraph { public List getInlinedMethods() { return inlinedMethods; } + + public boolean trackNodeSourcePosition() { + return trackNodeSourcePosition; + } + + public EconomicSet getFields() { + return fields; + } + + public boolean hasUnsafeAccess() { + return hasUnsafeAccess; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java index 9d51e2a00a9..2745f67fb80 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.nodes; +import org.graalvm.compiler.debug.DebugCloseable; import static org.graalvm.compiler.nodeinfo.InputType.Guard; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; @@ -80,16 +81,19 @@ public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowe } } + @SuppressWarnings("try") @Override public void lower(LoweringTool tool) { - if (graph().getGuardsStage().allowsFloatingGuards()) { - if (getAction() != DeoptimizationAction.None) { - ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode(); - this.replaceAtUsages(guard); - graph().removeFixed(this); + try (DebugCloseable position = this.withNodeSourcePosition()) { + if (graph().getGuardsStage().allowsFloatingGuards()) { + if (getAction() != DeoptimizationAction.None) { + ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode(); + this.replaceAtUsages(guard); + graph().removeFixed(this); + } + } else { + lowerToIf().lower(tool); } - } else { - lowerToIf().lower(tool); } } 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 390a66813c2..55bfa865f1c 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 @@ -244,7 +244,7 @@ public final class FrameState extends VirtualState implements IterableNodeType { if (fs == null) { return null; } - return new NodeSourcePosition(null, toSourcePosition(fs.outerFrameState()), fs.code.getMethod(), fs.bci); + return new NodeSourcePosition(toSourcePosition(fs.outerFrameState()), fs.code.getMethod(), fs.bci); } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java index be2fa0db07a..322f064628b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java @@ -146,6 +146,15 @@ public class GraphDecoder { public boolean isInlinedMethod() { return false; } + + public NodeSourcePosition getCallerBytecodePosition() { + return getCallerBytecodePosition(null); + } + + public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) { + return position; + } + } /** Decoding state maintained for each loop in the encoded graph. */ @@ -1001,7 +1010,7 @@ public class GraphDecoder { } protected void readProperties(MethodScope methodScope, Node node) { - node.setNodeSourcePosition((NodeSourcePosition) readObject(methodScope)); + NodeSourcePosition position = (NodeSourcePosition) readObject(methodScope); Fields fields = node.getNodeClass().getData(); for (int pos = 0; pos < fields.getCount(); pos++) { if (fields.getType(pos).isPrimitive()) { @@ -1012,6 +1021,9 @@ public class GraphDecoder { fields.putObject(node, pos, value); } } + if (graph.trackNodeSourcePosition() && position != null) { + node.setNodeSourcePosition(methodScope.getCallerBytecodePosition(position)); + } } /** @@ -1252,7 +1264,11 @@ public class GraphDecoder { long readerByteIndex = methodScope.reader.getByteIndex(); methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); NodeClass nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; - node = (FixedNode) graph.add(nodeClass.allocateInstance()); + Node stubNode = nodeClass.allocateInstance(); + if (graph.trackNodeSourcePosition()) { + stubNode.setNodeSourcePosition(NodeSourcePosition.placeholder(graph.method())); + } + node = (FixedNode) graph.add(stubNode); /* Properties and edges are not filled yet, the node remains uninitialized. */ methodScope.reader.setByteIndex(readerByteIndex); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java index 9f227d4847e..bbbb968f10c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java @@ -154,7 +154,7 @@ public class GraphEncoder { encoder.prepare(graph); encoder.finishPrepare(); int startOffset = encoder.encode(graph); - return new EncodedGraph(encoder.getEncoding(), startOffset, encoder.getObjects(), encoder.getNodeClasses(), graph.getAssumptions(), graph.getMethods()); + return new EncodedGraph(encoder.getEncoding(), startOffset, encoder.getObjects(), encoder.getNodeClasses(), graph); } public GraphEncoder(Architecture architecture) { @@ -288,8 +288,7 @@ public class GraphEncoder { } /* Check that the decoding of the encode graph is the same as the input. */ - assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()), - architecture); + assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph), architecture); return metadataStart; } @@ -436,6 +435,9 @@ public class GraphEncoder { public static boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encodedGraph, Architecture architecture) { DebugContext debug = originalGraph.getDebug(); StructuredGraph decodedGraph = new StructuredGraph.Builder(originalGraph.getOptions(), debug, AllowAssumptions.YES).method(originalGraph.method()).build(); + if (originalGraph.trackNodeSourcePosition()) { + decodedGraph.setTrackNodeSourcePosition(); + } GraphDecoder decoder = new GraphDecoder(architecture, decodedGraph); decoder.decode(encodedGraph); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java index c7165e6bcc3..24128da1d66 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java @@ -59,9 +59,9 @@ public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, public static final NodeClass TYPE = NodeClass.create(GuardNode.class); @Input(Condition) protected LogicNode condition; - protected final DeoptimizationReason reason; - protected JavaConstant speculation; + protected DeoptimizationReason reason; protected DeoptimizationAction action; + protected JavaConstant speculation; protected boolean negated; public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) { @@ -149,7 +149,13 @@ public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, negated = !negated; } + @Override public void setAction(DeoptimizationAction invalidaterecompile) { this.action = invalidaterecompile; } + + @Override + public void setReason(DeoptimizationReason reason) { + this.reason = reason; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java index 80c962f5d8f..a9789b1344e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java @@ -22,13 +22,20 @@ */ package org.graalvm.compiler.nodes; -import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; +import org.graalvm.collections.UnmodifiableEconomicMap; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.options.OptionValues; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.function.BiConsumer; /** * This class contains all inlining decisions performed on a graph during the compilation. @@ -40,8 +47,6 @@ import java.util.Map; *
  • the call target method
  • *
  • the reason for the inlining decision
  • *
  • the name of the phase in which the inlining decision took place
  • - *
  • the special {@link BytecodePositionWithId} value that describes the position in the bytecode - * together with the callsite-specific unique identifier
  • *
  • the inlining log of the inlined graph, or {@code null} if the decision was negative
  • * * @@ -49,99 +54,20 @@ import java.util.Map; * {@link StructuredGraph} by calling {@link #addDecision} whenever it decides to inline a method. * If there are invokes in the graph at the end of the respective phase, then that phase must call * {@link #addDecision} to log negative decisions. - * - * At the end of the compilation, the contents of the inlining log can be converted into a list of - * decisions by calling {@link #formatAsList} or into an inlining tree, by calling - * {@link #formatAsTree}. */ public class InliningLog { - /** - * A bytecode position with a unique identifier attached. - * - * The purpose of this class is to disambiguate callsites that are duplicated by a - * transformation (such as loop peeling or path duplication). - */ - public static final class BytecodePositionWithId extends BytecodePosition implements Comparable { - private final int id; - - public BytecodePositionWithId(BytecodePositionWithId caller, ResolvedJavaMethod method, int bci, int id) { - super(caller, method, bci); - this.id = id; - } - - public BytecodePositionWithId addCallerWithId(BytecodePositionWithId caller) { - if (getCaller() == null) { - return new BytecodePositionWithId(caller, getMethod(), getBCI(), id); - } else { - return new BytecodePositionWithId(getCaller().addCallerWithId(caller), getMethod(), getBCI(), id); - } - } - - public static BytecodePositionWithId create(FrameState state) { - return create(state, true); - } - - @SuppressWarnings("deprecation") - private static BytecodePositionWithId create(FrameState state, boolean topLevel) { - if (state == null) { - return null; - } - ResolvedJavaMethod method = state.getMethod(); - int bci = topLevel ? state.bci - 3 : state.bci; - int id = state.getId(); - return new BytecodePositionWithId(create(state.outerFrameState(), false), method, bci, id); - } - - @Override - public BytecodePositionWithId getCaller() { - return (BytecodePositionWithId) super.getCaller(); - } - - public BytecodePositionWithId withoutCaller() { - return new BytecodePositionWithId(null, getMethod(), getBCI(), id); - } - - public long getId() { - return id; - } - - @Override - public boolean equals(Object that) { - return super.equals(that) && this.id == ((BytecodePositionWithId) that).id; - } - - @Override - public int hashCode() { - return super.hashCode() ^ (id << 16); - } - - @Override - public int compareTo(BytecodePositionWithId that) { - int diff = this.getBCI() - that.getBCI(); - if (diff != 0) { - return diff; - } - diff = (int) (this.getId() - that.getId()); - return diff; - } - } public static final class Decision { private final boolean positive; private final String reason; private final String phase; private final ResolvedJavaMethod target; - private final BytecodePositionWithId position; - private final InliningLog childLog; - private Decision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position, InliningLog childLog) { - assert position != null; + private Decision(boolean positive, String reason, String phase, ResolvedJavaMethod target) { this.positive = positive; this.reason = reason; this.phase = phase; this.target = target; - this.position = position; - this.childLog = childLog; } public boolean isPositive() { @@ -156,123 +82,304 @@ public class InliningLog { return phase; } - public BytecodePositionWithId getPosition() { - return position; - } - - public InliningLog getChildLog() { - return childLog; - } - public ResolvedJavaMethod getTarget() { return target; } + + @Override + public String toString() { + return String.format("<%s> %s: %s", phase, target != null ? target.format("%H.%n(%p)") : "", reason); + } } - private static class Callsite { - public final List decisions; - public final Map children; - public final BytecodePositionWithId position; + private class Callsite { + public final List decisions; + public final List children; + public Callsite parent; + public ResolvedJavaMethod target; + public Invokable invoke; - Callsite(BytecodePositionWithId position) { - this.children = new HashMap<>(); - this.position = position; + Callsite(Callsite parent, Invokable originalInvoke) { + this.parent = parent; this.decisions = new ArrayList<>(); + this.children = new ArrayList<>(); + this.invoke = originalInvoke; } - public Callsite getOrCreateChild(BytecodePositionWithId fromRootPosition) { - Callsite child = children.get(fromRootPosition.withoutCaller()); - if (child == null) { - child = new Callsite(fromRootPosition); - children.put(fromRootPosition.withoutCaller(), child); - } + public Callsite addChild(Invokable childInvoke) { + Callsite child = new Callsite(this, childInvoke); + children.add(child); return child; } - public Callsite createCallsite(BytecodePositionWithId fromRootPosition, String decision) { - Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller()); - Callsite callsite = parent.getOrCreateChild(fromRootPosition); - callsite.decisions.add(decision); + public String positionString() { + if (parent == null) { + return ""; + } + return MetaUtil.appendLocation(new StringBuilder(100), parent.target, getBci()).toString(); + } + + public int getBci() { + return invoke != null ? invoke.bci() : -1; + } + } + + private final Callsite root; + private final EconomicMap leaves; + private final OptionValues options; + + public InliningLog(ResolvedJavaMethod rootMethod, OptionValues options) { + this.root = new Callsite(null, null); + this.root.target = rootMethod; + this.leaves = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE); + this.options = options; + } + + /** + * Add an inlining decision for the specified invoke. + * + * An inlining decision can be either positive or negative. A positive inlining decision must be + * logged after replacing an {@link Invoke} with a graph. In this case, the node replacement map + * and the {@link InliningLog} of the inlined graph must be provided. + */ + public void addDecision(Invokable invoke, boolean positive, String reason, String phase, EconomicMap replacements, InliningLog calleeLog) { + assert leaves.containsKey(invoke); + assert (!positive && replacements == null && calleeLog == null) || (positive && replacements != null && calleeLog != null); + Callsite callsite = leaves.get(invoke); + callsite.target = callsite.invoke.getTargetMethod(); + Decision decision = new Decision(positive, reason, phase, invoke.getTargetMethod()); + callsite.decisions.add(decision); + if (positive) { + leaves.removeKey(invoke); + EconomicMap mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE); + for (Callsite calleeChild : calleeLog.root.children) { + Callsite child = callsite.addChild(calleeChild.invoke); + copyTree(child, calleeChild, replacements, mapping); + } + MapCursor entries = calleeLog.leaves.getEntries(); + while (entries.advance()) { + Invokable invokeFromCallee = entries.getKey(); + Callsite callsiteFromCallee = entries.getValue(); + if (invokeFromCallee.asFixedNode().isDeleted()) { + // Some invoke nodes could have been removed by optimizations. + continue; + } + Invokable inlinedInvokeFromCallee = (Invokable) replacements.get(invokeFromCallee.asFixedNode()); + Callsite descendant = mapping.get(callsiteFromCallee); + leaves.put(inlinedInvokeFromCallee, descendant); + } + } + } + + /** + * Append the inlining decision tree from the specified log. + * + * The subtrees of the specified log are appended below the root of this log. This is usually + * called when a node in the graph is replaced with its snippet. + * + * @see InliningLog#addDecision + */ + public void addLog(UnmodifiableEconomicMap replacements, InliningLog replacementLog) { + EconomicMap mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE); + for (Callsite calleeChild : replacementLog.root.children) { + Callsite child = root.addChild(calleeChild.invoke); + copyTree(child, calleeChild, replacements, mapping); + } + MapCursor entries = replacementLog.leaves.getEntries(); + while (entries.advance()) { + Invokable replacementInvoke = entries.getKey(); + Callsite replacementCallsite = entries.getValue(); + if (replacementInvoke.asFixedNode().isDeleted()) { + // Some invoke nodes could have been removed by optimizations. + continue; + } + Invokable invoke = (Invokable) replacements.get(replacementInvoke.asFixedNode()); + Callsite callsite = mapping.get(replacementCallsite); + leaves.put(invoke, callsite); + } + } + + /** + * Completely replace the current log with the copy of the specified log. + * + * The precondition is that the current inlining log is completely empty. This is usually called + * when copying the entire graph. + * + * @see InliningLog#addDecision + */ + public void replaceLog(UnmodifiableEconomicMap replacements, InliningLog replacementLog) { + assert root.decisions.isEmpty(); + assert root.children.isEmpty(); + assert leaves.isEmpty(); + EconomicMap mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE); + copyTree(root, replacementLog.root, replacements, mapping); + MapCursor replacementEntries = replacementLog.leaves.getEntries(); + while (replacementEntries.advance()) { + Invokable replacementInvoke = replacementEntries.getKey(); + Callsite replacementSite = replacementEntries.getValue(); + Invokable invoke = (Invokable) replacements.get((Node) replacementInvoke); + Callsite site = mapping.get(replacementSite); + leaves.put(invoke, site); + } + } + + private void copyTree(Callsite site, Callsite replacementSite, UnmodifiableEconomicMap replacements, EconomicMap mapping) { + mapping.put(replacementSite, site); + site.target = replacementSite.target; + site.decisions.addAll(replacementSite.decisions); + site.invoke = replacementSite.invoke != null && replacementSite.invoke.asFixedNode().isAlive() ? (Invokable) replacements.get(replacementSite.invoke.asFixedNode()) : null; + for (Callsite replacementChild : replacementSite.children) { + Callsite child = new Callsite(site, null); + site.children.add(child); + copyTree(child, replacementChild, replacements, mapping); + } + } + + public void checkInvariants(StructuredGraph graph) { + for (Invoke invoke : graph.getInvokes()) { + assert leaves.containsKey(invoke) : "Invoke " + invoke + " not contained in the leaves."; + } + assert root.parent == null; + checkTreeInvariants(root); + } + + private void checkTreeInvariants(Callsite site) { + for (Callsite child : site.children) { + assert site == child.parent : "Callsite " + site + " with child " + child + " has an invalid parent pointer " + site; + checkTreeInvariants(child); + } + } + + private UpdateScope noUpdates = new UpdateScope((oldNode, newNode) -> { + }); + + private UpdateScope activated = null; + + /** + * Used to designate scopes in which {@link Invokable} registration or cloning should be handled + * differently. + */ + public final class UpdateScope implements AutoCloseable { + private BiConsumer updater; + + private UpdateScope(BiConsumer updater) { + this.updater = updater; + } + + public void activate() { + if (activated != null) { + throw GraalError.shouldNotReachHere("InliningLog updating already set."); + } + activated = this; + } + + @Override + public void close() { + if (GraalOptions.TraceInlining.getValue(options)) { + assert activated != null; + activated = null; + } + } + + public BiConsumer getUpdater() { + return updater; + } + } + + public BiConsumer getUpdateScope() { + if (activated == null) { return null; } + return activated.getUpdater(); + } - private Callsite getOrCreateCallsite(BytecodePositionWithId fromRootPosition) { - if (fromRootPosition == null) { - return this; - } else { - Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller()); - Callsite callsite = parent.getOrCreateChild(fromRootPosition); - return callsite; - } + /** + * Creates and sets a new update scope for the log. + * + * The specified {@code updater} is invoked when an {@link Invokable} node is registered or + * cloned. If the node is newly registered, then the first argument to the {@code updater} is + * {@code null}. If the node is cloned, then the first argument is the node it was cloned from. + * + * @param updater an operation taking a null (or the original node), and the registered (or + * cloned) {@link Invokable} + * @return a bound {@link UpdateScope} object, or a {@code null} if tracing is disabled + */ + public UpdateScope openUpdateScope(BiConsumer updater) { + if (GraalOptions.TraceInlining.getValue(options)) { + UpdateScope scope = new UpdateScope(updater); + scope.activate(); + return scope; + } else { + return null; } } - private final List decisions; - - public InliningLog() { - this.decisions = new ArrayList<>(); - } - - public List getDecisions() { - return decisions; - } - - public void addDecision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position, - InliningLog calleeLog) { - Decision decision = new Decision(positive, reason, phase, target, position, calleeLog); - decisions.add(decision); - } - - public String formatAsList() { - StringBuilder builder = new StringBuilder(); - formatAsList("", null, decisions, builder); - return builder.toString(); - } - - private void formatAsList(String phasePrefix, BytecodePositionWithId caller, List subDecisions, StringBuilder builder) { - for (Decision decision : subDecisions) { - String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase(); - String target = decision.getTarget().format("%H.%n(%p)"); - String positive = decision.isPositive() ? "inline" : "do not inline"; - BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller); - String position = " " + decision.getPosition().toString().replaceAll("\n", "\n "); - String line = String.format("<%s> %s %s: %s\n%s", phaseStack, positive, target, decision.getReason(), position); - builder.append(line).append(System.lineSeparator()); - if (decision.getChildLog() != null) { - formatAsList(phaseStack, absolutePosition, decision.getChildLog().getDecisions(), builder); - } + /** + * Creates a new update scope that does not update the log. + * + * This update scope will not add a newly created {@code Invokable} to the log, nor will it + * amend its position if it was cloned. Instead, users need to update the inlining log with the + * new {@code Invokable} on their own. + * + * @see #openUpdateScope + */ + public UpdateScope openDefaultUpdateScope() { + if (GraalOptions.TraceInlining.getValue(options)) { + noUpdates.activate(); + return noUpdates; + } else { + return null; } } + public boolean containsLeafCallsite(Invokable invokable) { + return leaves.containsKey(invokable); + } + + public void removeLeafCallsite(Invokable invokable) { + leaves.removeKey(invokable); + } + + public void trackNewCallsite(Invokable invoke) { + assert !leaves.containsKey(invoke); + Callsite callsite = new Callsite(root, invoke); + root.children.add(callsite); + leaves.put(invoke, callsite); + } + + public void trackDuplicatedCallsite(Invokable sibling, Invokable newInvoke) { + Callsite siblingCallsite = leaves.get(sibling); + Callsite parentCallsite = siblingCallsite.parent; + Callsite callsite = parentCallsite.addChild(newInvoke); + leaves.put(newInvoke, callsite); + } + + public void updateExistingCallsite(Invokable previousInvoke, Invokable newInvoke) { + Callsite callsite = leaves.get(previousInvoke); + leaves.removeKey(previousInvoke); + leaves.put(newInvoke, callsite); + callsite.invoke = newInvoke; + } + public String formatAsTree() { - Callsite root = new Callsite(null); - createTree("", null, root, decisions); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); formatAsTree(root, "", builder); return builder.toString(); } - private void createTree(String phasePrefix, BytecodePositionWithId caller, Callsite root, List subDecisions) { - for (Decision decision : subDecisions) { - String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase(); - String target = decision.getTarget().format("%H.%n(%p)"); - BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller); - String line = String.format("<%s> %s: %s", phaseStack, target, decision.getReason()); - root.createCallsite(absolutePosition, line); - if (decision.getChildLog() != null) { - createTree(phaseStack, absolutePosition, root, decision.getChildLog().getDecisions()); + private void formatAsTree(Callsite site, String indent, StringBuilder builder) { + String position = site.positionString(); + builder.append(indent).append("at ").append(position).append(": "); + if (site.decisions.isEmpty()) { + builder.append(System.lineSeparator()); + } else { + for (Decision decision : site.decisions) { + builder.append(decision.toString()); + builder.append(System.lineSeparator()); } } - } - - private void formatAsTree(Callsite site, String indent, StringBuilder builder) { - String position = site.position != null ? site.position.withoutCaller().toString() : ""; - String decision = String.join("; ", site.decisions); - String line = String.format("%s%s; %s", indent, position, decision); - builder.append(line).append(System.lineSeparator()); - String childIndent = indent + " "; - site.children.entrySet().stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).forEach(e -> { - formatAsTree(e.getValue(), childIndent, builder); - }); + for (Callsite child : site.children) { + formatAsTree(child, indent + " ", builder); + } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java new file mode 100644 index 00000000000..a98f34f009b --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 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. + * + * 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.nodes; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; + +/** + * A marker interface for nodes that represent calls to other methods. + */ +public interface Invokable { + ResolvedJavaMethod getTargetMethod(); + + int bci(); + + FixedNode asFixedNode(); + + /** + * Called on a {@link Invokable} node after it is registered with a graph. + * + * To override the default functionality, code that creates an {@link Invokable} should set the + * updating logic by calling {@link InliningLog#openUpdateScope}. + */ + default void updateInliningLogAfterRegister(StructuredGraph newGraph) { + InliningLog log = newGraph.getInliningLog(); + if (log.getUpdateScope() != null) { + log.getUpdateScope().accept(null, this); + } else { + assert !log.containsLeafCallsite(this); + log.trackNewCallsite(this); + } + } + + /** + * Called on a {@link Invokable} node after it was cloned from another node. + * + * This call is always preceded with a call to {@link Invokable#updateInliningLogAfterRegister}. + * + * To override the default functionality, code that creates an {@link Invokable} should set the + * updating logic by calling {@link InliningLog#openUpdateScope}. + */ + default void updateInliningLogAfterClone(Node other) { + if (GraalOptions.TraceInlining.getValue(asFixedNode().getOptions())) { + // At this point, the invokable node was already added to the inlining log + // in the call to updateInliningLogAfterRegister, so we need to remove it. + InliningLog log = asFixedNode().graph().getInliningLog(); + assert other instanceof Invokable; + if (log.getUpdateScope() != null) { + // InliningLog.UpdateScope determines how to update the log. + log.getUpdateScope().accept((Invokable) other, this); + } else if (other.graph() == this.asFixedNode().graph()) { + // This node was cloned as part of duplication. + // We need to add it as a sibling of the node other. + assert log.containsLeafCallsite(this) : "Node " + this + " not contained in the log."; + assert log.containsLeafCallsite((Invokable) other) : "Sibling " + other + " not contained in the log."; + log.removeLeafCallsite(this); + log.trackDuplicatedCallsite((Invokable) other, this); + } else { + // This node was added from a different graph. + // The adder is responsible for providing a context. + throw GraalError.shouldNotReachHere("No InliningLog.Update scope provided."); + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java index c9fd9344316..0e2ce6e8de4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java @@ -31,7 +31,7 @@ import org.graalvm.compiler.nodes.type.StampTool; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, FixedNodeInterface { +public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, FixedNodeInterface, Invokable { FixedNode next(); @@ -39,6 +39,7 @@ public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDur CallTargetNode callTarget(); + @Override int bci(); Node predecessor(); @@ -60,6 +61,11 @@ public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDur void setPolymorphic(boolean value); + @Override + default ResolvedJavaMethod getTargetMethod() { + return callTarget() != null ? callTarget().targetMethod() : null; + } + /** * Returns the {@linkplain ResolvedJavaMethod method} from which this invoke is executed. This * is the caller method and in the case of inlining may be different from the method of the diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java index ba2cbf4a23e..09020c405d3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java @@ -92,6 +92,16 @@ public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke this.useForInlining = true; } + @Override + protected void afterClone(Node other) { + updateInliningLogAfterClone(other); + } + + @Override + public FixedNode asFixedNode() { + return this; + } + @Override public CallTargetNode callTarget() { return callTarget; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java index 58a580a2606..5ba791a7e45 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java @@ -74,6 +74,16 @@ public final class InvokeWithExceptionNode extends ControlSplitNode implements I this.exceptionProbability = EXCEPTION_PROBA; } + @Override + protected void afterClone(Node other) { + updateInliningLogAfterClone(other); + } + + @Override + public FixedNode asFixedNode() { + return this; + } + public AbstractBeginNode exceptionEdge() { return exceptionEdge; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java index f1419ac2e91..b72645fa8bc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java @@ -105,6 +105,9 @@ public final class LoopExitNode extends BeginStateSplitNode implements IterableN Node prev = this.predecessor(); while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) { AbstractBeginNode begin = (AbstractBeginNode) prev; + if (begin.getNodeSourcePosition() != null || this.getNodeSourcePosition() == null || this.getNodeSourcePosition().isPlaceholder()) { + this.setNodeSourcePosition(begin.getNodeSourcePosition()); + } prev = prev.predecessor(); graph().removeFixed(begin); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java index 6fd619b78a5..f3b2f1fc7d5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java @@ -192,7 +192,7 @@ public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtual if (guard == null) { // Try to merge the pi node with a load node. - if (object instanceof ReadNode) { + if (object instanceof ReadNode && !object.hasMoreThanOneUsage()) { ReadNode readNode = (ReadNode) object; readNode.setStamp(readNode.stamp(NodeView.DEFAULT).improveWith(stamp)); return readNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java index 72f494a3536..2b75bb37c6f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java @@ -32,8 +32,12 @@ public interface StaticDeoptimizingNode extends ValueNodeInterface { DeoptimizationReason getReason(); + void setReason(DeoptimizationReason reason); + DeoptimizationAction getAction(); + void setAction(DeoptimizationAction action); + JavaConstant getSpeculation(); /** @@ -75,4 +79,15 @@ public interface StaticDeoptimizingNode extends ValueNodeInterface { } throw GraalError.shouldNotReachHere(); } + + static DeoptimizationAction mergeActions(DeoptimizationAction a1, DeoptimizationAction a2) { + if (a1 == a2) { + return a1; + } + if (a1 == DeoptimizationAction.InvalidateRecompile && a2 == DeoptimizationAction.InvalidateReprofile || + a1 == DeoptimizationAction.InvalidateReprofile && a2 == DeoptimizationAction.InvalidateRecompile) { + return DeoptimizationAction.InvalidateReprofile; + } + return null; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java index bff9ce3272e..93489ed3ee5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.nodes; +import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Default; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -39,6 +41,7 @@ import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.JavaMethodContext; +import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeMap; @@ -167,6 +170,7 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { private CompilationIdentifier compilationId = CompilationIdentifier.INVALID_COMPILATION_ID; private int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; private boolean useProfilingInfo = true; + private SourcePositionTracking trackNodeSourcePosition = Default; private final OptionValues options; private Cancellable cancellable = null; private final DebugContext debug; @@ -179,6 +183,7 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { this.options = options; this.debug = debug; this.assumptions = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null; + this.trackNodeSourcePosition = Graph.trackNodeSourcePositionDefault(options, debug); } /** @@ -187,7 +192,8 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { public Builder(OptionValues options, DebugContext debug) { this.options = options; this.debug = debug; - assumptions = null; + this.assumptions = null; + this.trackNodeSourcePosition = Graph.trackNodeSourcePositionDefault(options, debug); } public String getName() { @@ -257,13 +263,25 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { return this; } + public Builder trackNodeSourcePosition(SourcePositionTracking tracking) { + this.trackNodeSourcePosition = tracking; + return this; + } + + public Builder trackNodeSourcePosition(boolean flag) { + if (flag) { + this.trackNodeSourcePosition = SourcePositionTracking.Track; + } + return this; + } + public Builder callerContext(NodeSourcePosition context) { this.callerContext = context; return this; } public StructuredGraph build() { - return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable, callerContext); + return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, trackNodeSourcePosition, compilationId, options, debug, cancellable, callerContext); } } @@ -328,6 +346,7 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { Assumptions assumptions, SpeculationLog speculationLog, boolean useProfilingInfo, + SourcePositionTracking trackNodeSourcePosition, CompilationIdentifier compilationId, OptionValues options, DebugContext debug, @@ -342,8 +361,10 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { this.assumptions = assumptions; this.speculationLog = speculationLog; this.useProfilingInfo = useProfilingInfo; + this.trackNodeSourcePosition = trackNodeSourcePosition; + assert trackNodeSourcePosition != null; this.cancellable = cancellable; - this.inliningLog = new InliningLog(); + this.inliningLog = new InliningLog(rootMethod, options); this.callerContext = context; } @@ -457,6 +478,12 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { return inliningLog; } + public void logInliningTree() { + if (GraalOptions.TraceInlining.getValue(getOptions())) { + TTY.println(getInliningLog().formatAsTree()); + } + } + /** * Creates a copy of this graph. * @@ -471,6 +498,7 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { return copy(newName, duplicationMapCallback, compilationId, debugForCopy); } + @SuppressWarnings("try") private StructuredGraph copy(String newName, Consumer> duplicationMapCallback, CompilationIdentifier newCompilationId, DebugContext debugForCopy) { AllowAssumptions allowAssumptions = AllowAssumptions.ifNonNull(assumptions); StructuredGraph copy = new StructuredGraph(newName, @@ -479,6 +507,7 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { assumptions == null ? null : new Assumptions(), speculationLog, useProfilingInfo, + trackNodeSourcePosition, newCompilationId, getOptions(), debugForCopy, null, callerContext); if (allowAssumptions == AllowAssumptions.YES && assumptions != null) { @@ -491,7 +520,13 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { copy.isAfterExpandLogic = isAfterExpandLogic; EconomicMap replacements = EconomicMap.create(Equivalence.IDENTITY); replacements.put(start, copy.start); - UnmodifiableEconomicMap duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements); + UnmodifiableEconomicMap duplicates; + try (InliningLog.UpdateScope scope = copy.getInliningLog().openDefaultUpdateScope()) { + duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements); + if (scope != null) { + copy.getInliningLog().replaceLog(duplicates, this.getInliningLog()); + } + } if (duplicationMapCallback != null) { duplicationMapCallback.accept(duplicates); } @@ -951,6 +986,11 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { @Override protected void afterRegister(Node node) { assert hasValueProxies() || !(node instanceof ValueProxyNode); + if (GraalOptions.TraceInlining.getValue(getOptions())) { + if (node instanceof Invokable) { + ((Invokable) node).updateInliningLogAfterRegister(this); + } + } } public NodeSourcePosition getCallerContext() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java index ea18b63c66c..2ceef60ec67 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java @@ -25,12 +25,12 @@ package org.graalvm.compiler.nodes.calc; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; +import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Canonicalizable; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -209,7 +209,7 @@ public abstract class CompareNode extends BinaryOpLogicNode implements Canonical @SuppressWarnings("unused") protected LogicNode optimizeNormalizeCompare(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored, NodeView view) { - throw new GraalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored); + throw new PermanentBailoutException("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored); } private static LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond, boolean unorderedIsTrue) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java index eeb8dbac2fa..9037219d56f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -170,9 +170,9 @@ public final class ConditionalNode extends FloatingNode implements Canonicalizab return trueValue; } } else if (lessThan.getX() == falseValue && lessThan.getY() == trueValue) { - // return "x" for "x < y ? y : x" in case that we know "x <= y" + // return "y" for "x < y ? y : x" in case that we know "x <= y" if (falseValueStamp.upperBound() <= trueValueStamp.lowerBound()) { - return falseValue; + return trueValue; } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java index 0e601f2910e..35304e531ba 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java @@ -139,6 +139,15 @@ public abstract class IntegerConvertNode extends UnaryNode implements A return convert(input, stamp, true, view); } + public static ValueNode convertUnsigned(ValueNode input, Stamp stamp, StructuredGraph graph, NodeView view) { + ValueNode convert = convert(input, stamp, true, view); + if (!convert.isAlive()) { + assert !convert.isDeleted(); + convert = graph.addOrUniqueWithInputs(convert); + } + return convert; + } + public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend, NodeView view) { IntegerStamp fromStamp = (IntegerStamp) input.stamp(view); IntegerStamp toStamp = (IntegerStamp) stamp; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java index fd4ad73312d..62358f298a3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.nodes.calc; +import static jdk.vm.ci.code.CodeUtil.mask; + import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -70,8 +72,8 @@ public abstract class IntegerLowerThanNode extends CompareNode { private Stamp getSucceedingStampForX(boolean mirror, boolean strict, Stamp xStampGeneric, Stamp yStampGeneric, ValueNode forX, ValueNode forY) { Stamp s = getSucceedingStampForX(mirror, strict, xStampGeneric, yStampGeneric); - if (s != null) { - return s; + if (s != null && s.isUnrestricted()) { + s = null; } if (forY instanceof AddNode && xStampGeneric instanceof IntegerStamp) { IntegerStamp xStamp = (IntegerStamp) xStampGeneric; @@ -88,11 +90,15 @@ public abstract class IntegerLowerThanNode extends CompareNode { IntegerStamp result = getOp().getSucceedingStampForXLowerXPlusA(mirror, strict, aStamp); result = (IntegerStamp) xStamp.tryImproveWith(result); if (result != null) { - return result; + if (s != null) { + s = s.improveWith(result); + } else { + s = result; + } } } } - return null; + return s; } private Stamp getSucceedingStampForX(boolean mirror, boolean strict, Stamp xStampGeneric, Stamp yStampGeneric) { @@ -278,7 +284,7 @@ public abstract class IntegerLowerThanNode extends CompareNode { } low += 1; } - if (compare(low, lowerBound(xStamp)) > 0) { + if (compare(low, lowerBound(xStamp)) > 0 || upperBound(xStamp) != (xStamp.upperBound() & mask(xStamp.getBits()))) { return forInteger(bits, low, upperBound(xStamp)); } } else { @@ -290,7 +296,7 @@ public abstract class IntegerLowerThanNode extends CompareNode { } low -= 1; } - if (compare(low, upperBound(xStamp)) < 0) { + if (compare(low, upperBound(xStamp)) < 0 || lowerBound(xStamp) != (xStamp.lowerBound() & mask(xStamp.getBits()))) { return forInteger(bits, lowerBound(xStamp), low); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java index d63cd4d311b..9b6d96e07ac 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java @@ -24,6 +24,7 @@ package org.graalvm.compiler.nodes.extended; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,7 +41,6 @@ import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.FixedGuardNode; -import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; @@ -316,7 +316,7 @@ public final class IntegerSwitchNode extends SwitchNode implements LIRLowerable, private void doReplace(ValueNode newValue, List newKeyDatas, ArrayList newSuccessors, int newDefaultSuccessor, double newDefaultProbability) { /* Sort the new keys (invariant of the IntegerSwitchNode). */ - newKeyDatas.sort((k1, k2) -> k1.key - k2.key); + newKeyDatas.sort(Comparator.comparingInt(k -> k.key)); /* Create the final data arrays. */ int newKeyCount = newKeyDatas.size(); @@ -349,20 +349,27 @@ public final class IntegerSwitchNode extends SwitchNode implements LIRLowerable, } } - /* Remove dead successors. */ - for (int i = 0; i < blockSuccessorCount(); i++) { - AbstractBeginNode successor = blockSuccessor(i); - if (!newSuccessors.contains(successor)) { - FixedNode fixedBranch = successor; - fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); - GraphUtil.killCFG(fixedBranch); - } - setBlockSuccessor(i, null); - } + /* + * Collect dead successors. Successors have to be cleaned before adding the new node to the + * graph. + */ + List deadSuccessors = successors.filter(s -> !newSuccessors.contains(s)).snapshot(); + successors.clear(); - /* Create the new switch node and replace ourself with it. */ + /* + * Create the new switch node. This is done before removing dead successors as `killCFG` + * could edit some of the inputs (e.g., if `newValue` is a loop-phi of the loop that dies + * while removing successors). + */ AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]); SwitchNode newSwitch = graph().add(new IntegerSwitchNode(newValue, successorsArray, newKeys, newKeyProbabilities, newKeySuccessors)); + + /* Remove dead successors. */ + for (AbstractBeginNode successor : deadSuccessors) { + GraphUtil.killCFG(successor); + } + + /* Replace ourselves with the new switch */ ((FixedWithNextNode) predecessor()).setNext(newSwitch); GraphUtil.killWithUnusedFloatingInputs(this); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java index 9ea105ad071..8154cd2e69b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java @@ -25,10 +25,16 @@ package org.graalvm.compiler.nodes.graphbuilderconf; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.ValueNode; +import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ResolvedJavaType; public interface ClassInitializationPlugin extends GraphBuilderPlugin { boolean shouldApply(GraphBuilderContext builder, ResolvedJavaType type); ValueNode apply(GraphBuilderContext builder, ResolvedJavaType type, FrameState frameState); + + boolean supportsLazyInitialization(ConstantPool cp); + + void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int bytecode); + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java index 9bd955005ae..74c239b364b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java @@ -228,8 +228,7 @@ public class GraphBuilderConfiguration { } protected GraphBuilderConfiguration(boolean eagerResolving, boolean unresolvedIsError, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints, - boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes, - Plugins plugins) { + boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes, Plugins plugins) { this.eagerResolving = eagerResolving; this.unresolvedIsError = unresolvedIsError; this.bytecodeExceptionMode = bytecodeExceptionMode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java index f1599601c18..abfeb47731f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java @@ -45,33 +45,35 @@ public interface InlineInvokePlugin extends GraphBuilderPlugin { * Denotes a call site that must not be inlined and should be implemented by a node that * does not speculate on the call not raising an exception. */ - public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, null); + public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, null, null); /** * Denotes a call site must not be inlined and can be implemented by a node that speculates * the call will not throw an exception. */ - public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, null); + public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, null, null); /** * Denotes a call site must not be inlined and the execution should be transferred to * interpreter in case of an exception. */ - public static final InlineInfo DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION = new InlineInfo(null, null); + public static final InlineInfo DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION = new InlineInfo(null, null, null); private final ResolvedJavaMethod methodToInline; + private final ResolvedJavaMethod originalMethod; private final BytecodeProvider intrinsicBytecodeProvider; public static InlineInfo createStandardInlineInfo(ResolvedJavaMethod methodToInline) { - return new InlineInfo(methodToInline, null); + return new InlineInfo(methodToInline, null, null); } - public static InlineInfo createIntrinsicInlineInfo(ResolvedJavaMethod methodToInline, BytecodeProvider intrinsicBytecodeProvider) { - return new InlineInfo(methodToInline, intrinsicBytecodeProvider); + public static InlineInfo createIntrinsicInlineInfo(ResolvedJavaMethod methodToInline, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider) { + return new InlineInfo(methodToInline, originalMethod, intrinsicBytecodeProvider); } - private InlineInfo(ResolvedJavaMethod methodToInline, BytecodeProvider intrinsicBytecodeProvider) { + private InlineInfo(ResolvedJavaMethod methodToInline, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider) { this.methodToInline = methodToInline; + this.originalMethod = originalMethod; this.intrinsicBytecodeProvider = intrinsicBytecodeProvider; } @@ -86,6 +88,14 @@ public interface InlineInvokePlugin extends GraphBuilderPlugin { return methodToInline != null; } + /** + * Returns the original method if this is an inline of an intrinsic, or {@code null} if the + * call site must not be inlined. + */ + public ResolvedJavaMethod getOriginalMethod() { + return originalMethod; + } + /** * Gets the provider of bytecode to be parsed for {@link #getMethodToInline()} if is is an * intrinsic for the original method (i.e., the {@code method} passed to diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java index f06676378ef..7a392c82eca 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java @@ -29,6 +29,7 @@ import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI; import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; +import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -54,12 +55,12 @@ public class IntrinsicContext { /** * Method being intrinsified. */ - final ResolvedJavaMethod method; + final ResolvedJavaMethod originalMethod; /** * Method providing the intrinsic implementation. */ - final ResolvedJavaMethod intrinsic; + final ResolvedJavaMethod intrinsicMethod; /** * Provider of bytecode to be parsed for a method that is part of an intrinsic. @@ -76,13 +77,14 @@ public class IntrinsicContext { public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext, boolean allowPartialIntrinsicArgumentMismatch) { - this.method = method; - this.intrinsic = intrinsic; + this.originalMethod = method; + this.intrinsicMethod = intrinsic; this.bytecodeProvider = bytecodeProvider; assert bytecodeProvider != null; this.compilationContext = compilationContext; this.allowPartialIntrinsicArgumentMismatch = allowPartialIntrinsicArgumentMismatch; assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)"); + assert !method.equals(intrinsic) || method.getAnnotation(MethodSubstitution.class) == null : "method and intrinsic must be different: " + method + " " + intrinsic; } /** @@ -98,14 +100,14 @@ public class IntrinsicContext { * Gets the method being intrinsified. */ public ResolvedJavaMethod getOriginalMethod() { - return method; + return originalMethod; } /** * Gets the method providing the intrinsic implementation. */ public ResolvedJavaMethod getIntrinsicMethod() { - return intrinsic; + return intrinsicMethod; } /** @@ -121,9 +123,11 @@ public class IntrinsicContext { * intrinsification falls back to the original method. */ public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) { - return method.equals(targetMethod) || intrinsic.equals(targetMethod); + return originalMethod.equals(targetMethod) || intrinsicMethod.equals(targetMethod); } + private NodeSourcePosition nodeSourcePosition; + public boolean isPostParseInlined() { return compilationContext.equals(INLINE_AFTER_PARSING); } @@ -132,6 +136,15 @@ public class IntrinsicContext { return compilationContext.equals(ROOT_COMPILATION); } + public NodeSourcePosition getNodeSourcePosition() { + return nodeSourcePosition; + } + + public void setNodeSourcePosition(NodeSourcePosition position) { + assert nodeSourcePosition == null : "can only be set once"; + this.nodeSourcePosition = position; + } + /** * Denotes the compilation context in which an intrinsic is being parsed. */ @@ -182,7 +195,9 @@ public class IntrinsicContext { // Only the last side effect on any execution path in a replacement // can inherit the stateAfter of the replaced node FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI)); - invalid.setNodeSourcePosition(sourcePosition); + if (graph.trackNodeSourcePosition()) { + invalid.setNodeSourcePosition(sourcePosition); + } for (StateSplit lastSideEffect : sideEffects.sideEffects()) { lastSideEffect.setStateAfter(invalid); } @@ -194,7 +209,9 @@ public class IntrinsicContext { } else { frameState = graph.add(new FrameState(AFTER_BCI)); } - frameState.setNodeSourcePosition(sourcePosition); + if (graph.trackNodeSourcePosition()) { + frameState.setNodeSourcePosition(sourcePosition); + } return frameState; } else { if (forStateSplit instanceof AbstractMergeNode) { @@ -202,12 +219,16 @@ public class IntrinsicContext { if (sideEffects.isAfterSideEffect()) { // A merge after one or more side effects FrameState frameState = graph.add(new FrameState(AFTER_BCI)); - frameState.setNodeSourcePosition(sourcePosition); + if (graph.trackNodeSourcePosition()) { + frameState.setNodeSourcePosition(sourcePosition); + } return frameState; } else { // A merge before any side effects FrameState frameState = graph.add(new FrameState(BEFORE_BCI)); - frameState.setNodeSourcePosition(sourcePosition); + if (graph.trackNodeSourcePosition()) { + frameState.setNodeSourcePosition(sourcePosition); + } return frameState; } } else { @@ -219,6 +240,6 @@ public class IntrinsicContext { @Override public String toString() { - return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}"; + return "Intrinsic{original: " + originalMethod.format("%H.%n(%p)") + ", intrinsic: " + intrinsicMethod.format("%H.%n(%p)") + ", context: " + compilationContext + "}"; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java index 8a13be8e84e..3e5ef1d29d8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java @@ -55,18 +55,24 @@ public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonica public static final NodeClass TYPE = NodeClass.create(InstanceOfDynamicNode.class); private final boolean allowNull; + private final boolean exact; - public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull) { - LogicNode synonym = findSynonym(assumptions, constantReflection, mirror, object, allowNull); + public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull, boolean exact) { + LogicNode synonym = findSynonym(assumptions, constantReflection, mirror, object, allowNull, exact); if (synonym != null) { return synonym; } - return new InstanceOfDynamicNode(mirror, object, allowNull); + return new InstanceOfDynamicNode(mirror, object, allowNull, exact); } - protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object, boolean allowNull) { + public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull) { + return create(assumptions, constantReflection, mirror, object, allowNull, false); + } + + protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object, boolean allowNull, boolean exact) { super(TYPE, mirror, object); this.allowNull = allowNull; + this.exact = exact; assert mirror.getStackKind() == JavaKind.Object || mirror.getStackKind() == JavaKind.Illegal : mirror.getStackKind(); } @@ -83,8 +89,7 @@ public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonica tool.getLowerer().lower(this, tool); } - private static LogicNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode forMirror, ValueNode forObject, - boolean allowNull) { + private static LogicNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode forMirror, ValueNode forObject, boolean allowNull, boolean exact) { if (forMirror.isConstant()) { ResolvedJavaType t = constantReflection.asJavaType(forMirror.asConstant()); if (t != null) { @@ -95,7 +100,7 @@ public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonica return LogicConstantNode.contradiction(); } } else { - TypeReference type = TypeReference.createTrusted(assumptions, t); + TypeReference type = exact ? TypeReference.createExactTrusted(t) : TypeReference.createTrusted(assumptions, t); if (allowNull) { return InstanceOfNode.createAllowNull(type, forObject, null, null); } else { @@ -117,7 +122,7 @@ public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonica @Override public LogicNode canonical(CanonicalizerTool tool, ValueNode forMirror, ValueNode forObject) { - LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull); + LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull, exact); if (result != null) { return result; } @@ -133,6 +138,10 @@ public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonica return allowNull; } + public boolean isExact() { + return exact; + } + @Override public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) { return null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java index 999e6f11761..b0d46a0770a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java @@ -26,6 +26,7 @@ import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.SnippetTemplateCache; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; @@ -50,9 +51,10 @@ public interface Replacements { * Gets the snippet graph derived from a given method. * * @param args arguments to the snippet if available, otherwise {@code null} + * @param trackNodeSourcePosition * @return the snippet graph, if any, that is derived from {@code method} */ - StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args); + StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition); /** * Gets the snippet graph derived from a given method. @@ -61,23 +63,25 @@ public interface Replacements { * recursive call and won't be processed for {@linkplain MethodSubstitution * substitutions}. * @param args arguments to the snippet if available, otherwise {@code null} + * @param trackNodeSourcePosition * @return the snippet graph, if any, that is derived from {@code method} */ - StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args); + StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition); /** * Registers a method as snippet. */ - void registerSnippet(ResolvedJavaMethod method); + void registerSnippet(ResolvedJavaMethod method, boolean trackNodeSourcePosition); /** * Gets a graph that is a substitution for a given method. * * @param invokeBci the call site BCI if this request is made for inlining a substitute * otherwise {@code -1} + * @param trackNodeSourcePosition * @return the graph, if any, that is a substitution for {@code method} */ - StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci); + StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition); /** * Gets the substitute bytecode for a given method. @@ -88,7 +92,8 @@ public interface Replacements { Bytecode getSubstitutionBytecode(ResolvedJavaMethod method); /** - * Determines if there may be a {@linkplain #getSubstitution(ResolvedJavaMethod, int) + * Determines if there may be a + * {@linkplain #getSubstitution(ResolvedJavaMethod, int, boolean, NodeSourcePosition) * substitution graph} for a given method. * * A call to {@link #getSubstitution} may still return {@code null} for {@code method} and diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java index b23c25592b7..9e5db5ae96c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.phases.common; +import static org.graalvm.compiler.nodes.StaticDeoptimizingNode.mergeActions; + import java.util.ArrayDeque; import java.util.Deque; import java.util.List; @@ -30,6 +32,7 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; import org.graalvm.collections.MapCursor; import org.graalvm.collections.Pair; +import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; @@ -92,6 +95,7 @@ import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; import org.graalvm.compiler.phases.tiers.PhaseContext; +import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.TriState; @@ -146,8 +150,8 @@ public class ConditionalEliminationPhase extends BasePhase { } protected ControlFlowGraph.RecursiveVisitor createVisitor(StructuredGraph graph, @SuppressWarnings("unused") ControlFlowGraph cfg, BlockMap> blockToNodes, - @SuppressWarnings("unused") NodeMap nodeToBlock, PhaseContext context) { - return new Instance(graph, blockToNodes, context); + NodeMap nodeToBlock, PhaseContext context) { + return new Instance(graph, blockToNodes, nodeToBlock, context); } public static class MoveGuardsUpwards implements ControlFlowGraph.RecursiveVisitor { @@ -244,6 +248,7 @@ public class ConditionalEliminationPhase extends BasePhase { public static class Instance implements ControlFlowGraph.RecursiveVisitor { protected final NodeMap map; protected final BlockMap> blockToNodes; + protected final NodeMap nodeToBlock; protected final CanonicalizerTool tool; protected final NodeStack undoOperations; protected final StructuredGraph graph; @@ -255,10 +260,11 @@ public class ConditionalEliminationPhase extends BasePhase { */ private Deque pendingTests; - public Instance(StructuredGraph graph, BlockMap> blockToNodes, PhaseContext context) { + public Instance(StructuredGraph graph, BlockMap> blockToNodes, NodeMap nodeToBlock, PhaseContext context) { this.graph = graph; this.debug = graph.getDebug(); this.blockToNodes = blockToNodes; + this.nodeToBlock = nodeToBlock; this.undoOperations = new NodeStack(); this.map = graph.createNodeMap(); pendingTests = new ArrayDeque<>(); @@ -614,7 +620,7 @@ public class ConditionalEliminationPhase extends BasePhase { * never be replaced with a pi node via canonicalization). */ private static Stamp getOtherSafeStamp(ValueNode x) { - if (x.isConstant()) { + if (x.isConstant() || x.graph().isAfterFixedReadPhase()) { return x.stamp(NodeView.DEFAULT); } return x.stamp(NodeView.DEFAULT).unrestricted(); @@ -633,6 +639,23 @@ public class ConditionalEliminationPhase extends BasePhase { return recursiveFoldStamp(node); } + /** + * Look for a preceding guard whose condition is implied by {@code thisGuard}. If we find + * one, try to move this guard just above that preceding guard so that we can fold it: + * + *
    +         *     guard(C1); // preceding guard
    +         *     ...
    +         *     guard(C2); // thisGuard
    +         * 
    + * + * If C2 => C1, transform to: + * + *
    +         *     guard(C2);
    +         *     ...
    +         * 
    + */ protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) { for (DeoptimizingGuard pendingGuard : pendingTests) { LogicNode pendingCondition = pendingGuard.getCondition(); @@ -661,12 +684,9 @@ public class ConditionalEliminationPhase extends BasePhase { if (result.isKnown()) { /* * The test case be folded using the information available but the test can only - * be moved up if we're sure there's no schedule dependence. For now limit it to - * the original node and constants. + * be moved up if we're sure there's no schedule dependence. */ - InputFilter v = new InputFilter(original); - thisGuard.getCondition().applyInputs(v); - if (v.ok && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) { + if (canScheduleAbove(thisGuard.getCondition(), pendingGuard.asNode(), original) && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) { return true; } } @@ -674,8 +694,30 @@ public class ConditionalEliminationPhase extends BasePhase { return false; } + private boolean canScheduleAbove(Node n, Node target, ValueNode knownToBeAbove) { + Block targetBlock = nodeToBlock.get(target); + Block testBlock = nodeToBlock.get(n); + if (targetBlock != null && testBlock != null) { + if (targetBlock == testBlock) { + for (Node fixed : blockToNodes.get(targetBlock)) { + if (fixed == n) { + return true; + } else if (fixed == target) { + break; + } + } + } else if (AbstractControlFlowGraph.dominates(testBlock, targetBlock)) { + return true; + } + } + InputFilter v = new InputFilter(knownToBeAbove); + n.applyInputs(v); + return v.ok; + } + protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, boolean outcome, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) { - if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) { + DeoptimizationAction action = mergeActions(otherGuard.getAction(), thisGuard.getAction()); + if (action != null && otherGuard.getSpeculation() == thisGuard.getSpeculation()) { LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs(); /* * We have ...; guard(C1); guard(C2);... @@ -688,12 +730,16 @@ public class ConditionalEliminationPhase extends BasePhase { * * - If C2 => !C1, `mustDeopt` is true and we transform to ..; guard(C1); deopt; */ + // for the second case, the action of the deopt is copied from there: + thisGuard.setAction(action); GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> { // `result` is `outcome`, `guard` is `otherGuard` boolean mustDeopt = result == otherGuard.isNegated(); if (rewireGuardFunction.rewire(guard, mustDeopt == thisGuard.isNegated(), innerGuardedValueStamp, newInput)) { if (!mustDeopt) { otherGuard.setCondition(condition, thisGuard.isNegated()); + otherGuard.setAction(action); + otherGuard.setReason(thisGuard.getReason()); } return true; } @@ -783,16 +829,6 @@ public class ConditionalEliminationPhase extends BasePhase { } } else if (node instanceof BinaryOpLogicNode) { BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node; - infoElement = getInfoElements(binaryOpLogicNode); - while (infoElement != null) { - if (infoElement.getStamp().equals(StampFactory.contradiction())) { - return rewireGuards(infoElement.getGuard(), false, infoElement.getProxifiedInput(), null, rewireGuardFunction); - } else if (infoElement.getStamp().equals(StampFactory.tautology())) { - return rewireGuards(infoElement.getGuard(), true, infoElement.getProxifiedInput(), null, rewireGuardFunction); - } - infoElement = nextElement(infoElement); - } - ValueNode x = binaryOpLogicNode.getX(); ValueNode y = binaryOpLogicNode.getY(); infoElement = getInfoElements(x); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java index 641fbd69bd7..2760bbf3351 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java @@ -131,6 +131,7 @@ public class ConvertDeoptimizeToGuardPhase extends BasePhase { } } + @SuppressWarnings("try") private void processFixedGuardAndMerge(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi, AbstractMergeNode merge) { List mergePredecessors = merge.cfgPredecessors().snapshot(); @@ -152,11 +153,14 @@ public class ConvertDeoptimizeToGuardPhase extends BasePhase { ys = yPhi.valueAt(mergePredecessor).asConstant(); } if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) { - propagateFixed(mergePredecessor, fixedGuard, context.getLowerer()); + try (DebugCloseable position = fixedGuard.withNodeSourcePosition()) { + propagateFixed(mergePredecessor, fixedGuard, context.getLowerer()); + } } } } + @SuppressWarnings("try") private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) { Node current = from; while (current != null) { @@ -179,32 +183,36 @@ public class ConvertDeoptimizeToGuardPhase extends BasePhase { return; } else if (current.predecessor() instanceof IfNode) { IfNode ifNode = (IfNode) current.predecessor(); - StructuredGraph graph = ifNode.graph(); - LogicNode conditionNode = ifNode.condition(); - boolean negateGuardCondition = current == ifNode.trueSuccessor(); - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition)); - FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); - AbstractBeginNode survivingSuccessor; - if (negateGuardCondition) { - survivingSuccessor = ifNode.falseSuccessor(); - } else { - survivingSuccessor = ifNode.trueSuccessor(); - } - graph.removeSplitPropagate(ifNode, survivingSuccessor); + // Prioritize the source position of the IfNode + try (DebugCloseable closable = ifNode.withNodeSourcePosition()) { + StructuredGraph graph = ifNode.graph(); + LogicNode conditionNode = ifNode.condition(); + boolean negateGuardCondition = current == ifNode.trueSuccessor(); + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition)); - Node newGuard = guard; - if (survivingSuccessor instanceof LoopExitNode) { - newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph); - } - survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard); + FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); + AbstractBeginNode survivingSuccessor; + if (negateGuardCondition) { + survivingSuccessor = ifNode.falseSuccessor(); + } else { + survivingSuccessor = ifNode.trueSuccessor(); + } + graph.removeSplitPropagate(ifNode, survivingSuccessor); - graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor); - FixedNode next = pred.next(); - pred.setNext(guard); - guard.setNext(next); - SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider); - survivingSuccessor.simplify(simplifierTool); - return; + Node newGuard = guard; + if (survivingSuccessor instanceof LoopExitNode) { + newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph); + } + survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard); + + graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor); + FixedNode next = pred.next(); + pred.setNext(guard); + guard.setNext(next); + SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider); + survivingSuccessor.simplify(simplifierTool); + return; + } } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) { assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start()); moveAsDeoptAfter((AbstractBeginNode) current, deopt); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java new file mode 100644 index 00000000000..decd7c57726 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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. + * + * 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.phases.common; + +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class NodeCounterPhase extends BasePhase { + + public static class Options { + // @formatter:off + @Option(help = "Counts the number of instances of each node class.", type = OptionType.Debug) + public static final OptionKey NodeCounters = new OptionKey<>(false); + // @formatter:on + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + for (Node node : graph.getNodes()) { + DebugContext.counter("NodeCounter_%s", + node.getNodeClass().getClazz().getSimpleName()).increment(node.getDebug()); + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java index bf625ed550b..2cf2f0c5012 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java @@ -39,6 +39,7 @@ import org.graalvm.collections.Equivalence; import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -47,8 +48,8 @@ import org.graalvm.compiler.core.common.util.Util; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.GraalGraphError; -import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; +import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.graph.Graph.NodeEventScope; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeInputList; @@ -68,6 +69,7 @@ import org.graalvm.compiler.nodes.FixedGuardNode; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.InliningLog; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.InvokeNode; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; @@ -82,6 +84,7 @@ import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.UnwindNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.IsNullNode; @@ -102,7 +105,6 @@ import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -118,43 +120,104 @@ public class InliningUtil extends ValueMergeUtil { printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args); } + /** + * @see #printInlining + */ private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) { if (HotSpotPrintInlining.getValue(invoke.asNode().getOptions())) { Util.printInlining(method, invoke.bci(), inliningDepth, success, msg, args); } } - public static void logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) { - logInliningDecision(info, inliningDepth, allowLogging, true, msg, args); + /** + * Trace a decision to inline a method. + * + * This prints a HotSpot-style inlining message to the console, and it also logs the decision to + * the logging stream. + * + * Phases that perform inlining should use this method to trace the inlining decisions, and use + * the {@link #traceNotInlinedMethod} methods only for debugging purposes. + */ + public static void traceInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) { + traceMethod(info, inliningDepth, allowLogging, true, msg, args); } - public static void logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) { - logInliningDecision(info, inliningDepth, true, false, msg, args); + /** + * Trace a decision to inline a method. + * + * This prints a HotSpot-style inlining message to the console, and it also logs the decision to + * the logging stream. + * + * Phases that perform inlining should use this method to trace the inlining decisions, and use + * the {@link #traceNotInlinedMethod} methods only for debugging purposes. + */ + public static void traceInlinedMethod(Invoke invoke, int inliningDepth, boolean allowLogging, ResolvedJavaMethod method, String msg, Object... args) { + traceMethod(invoke, inliningDepth, allowLogging, true, method, msg, args); } - public static void logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) { + /** + * Trace a decision to not inline a method. + * + * This prints a HotSpot-style inlining message to the console, and it also logs the decision to + * the logging stream. + * + * Phases that perform inlining should use this method to trace the inlining decisions, and use + * the {@link #traceNotInlinedMethod} methods only for debugging purposes. + */ + public static void traceNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) { + traceMethod(info, inliningDepth, true, false, msg, args); + } + + /** + * Trace a decision about not inlining a method. + * + * This prints a HotSpot-style inlining message to the console, and it also logs the decision to + * the logging stream. + * + * Phases that perform inlining should use this method to trace the inlining decisions, and use + * the {@link #traceNotInlinedMethod} methods only for debugging purposes. + */ + public static void traceNotInlinedMethod(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) { + traceMethod(invoke, inliningDepth, true, false, method, msg, args); + } + + private static void traceMethod(Invoke invoke, int inliningDepth, boolean allowLogging, boolean success, ResolvedJavaMethod method, String msg, Object... args) { + if (allowLogging) { + DebugContext debug = invoke.asNode().getDebug(); + printInlining(method, invoke, inliningDepth, success, msg, args); + if (shouldLogMethod(debug)) { + String methodString = methodName(method, invoke); + logMethod(debug, methodString, success, msg, args); + } + } + } + + private static void traceMethod(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) { if (allowLogging) { printInlining(info, inliningDepth, success, msg, args); DebugContext debug = info.graph().getDebug(); - if (shouldLogInliningDecision(debug)) { - logInliningDecision(debug, methodName(info), success, msg, args); + if (shouldLogMethod(debug)) { + logMethod(debug, methodName(info), success, msg, args); } } } - @SuppressWarnings("try") + /** + * Output a generic inlining decision to the logging stream (e.g. inlining termination + * condition). + * + * Used for debugging purposes. + */ public static void logInliningDecision(DebugContext debug, final String msg, final Object... args) { - try (DebugContext.Scope s = debug.scope(inliningDecisionsScopeString)) { - // Can't use log here since we are varargs - if (debug.isLogEnabled()) { - debug.logv(msg, args); - } - } + logInlining(debug, msg, args); } + /** + * Output a decision about not inlining a method to the logging stream, for debugging purposes. + */ public static void logNotInlinedMethod(Invoke invoke, String msg) { DebugContext debug = invoke.asNode().getDebug(); - if (shouldLogInliningDecision(debug)) { + if (shouldLogMethod(debug)) { String methodString = invoke.toString(); if (invoke.callTarget() == null) { methodString += " callTarget=null"; @@ -164,33 +227,30 @@ public class InliningUtil extends ValueMergeUtil { methodString += " " + targetName; } } - logInliningDecision(debug, methodString, false, msg, new Object[0]); + logMethod(debug, methodString, false, msg, new Object[0]); } } - public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) { - logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]); - } - - public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) { - DebugContext debug = invoke.asNode().getDebug(); - printInlining(method, invoke, inliningDepth, false, msg, args); - if (shouldLogInliningDecision(debug)) { - String methodString = methodName(method, invoke); - logInliningDecision(debug, methodString, false, msg, args); - } - } - - private static void logInliningDecision(DebugContext debug, final String methodString, final boolean success, final String msg, final Object... args) { + private static void logMethod(DebugContext debug, final String methodString, final boolean success, final String msg, final Object... args) { String inliningMsg = "inlining " + methodString + ": " + msg; if (!success) { inliningMsg = "not " + inliningMsg; } - logInliningDecision(debug, inliningMsg, args); + logInlining(debug, inliningMsg, args); } @SuppressWarnings("try") - public static boolean shouldLogInliningDecision(DebugContext debug) { + private static void logInlining(DebugContext debug, final String msg, final Object... args) { + try (DebugContext.Scope s = debug.scope(inliningDecisionsScopeString)) { + // Can't use log here since we are varargs + if (debug.isLogEnabled()) { + debug.logv(msg, args); + } + } + } + + @SuppressWarnings("try") + private static boolean shouldLogMethod(DebugContext debug) { try (DebugContext.Scope s = debug.scope(inliningDecisionsScopeString)) { return debug.isLogEnabled(); } @@ -269,7 +329,8 @@ public class InliningUtil extends ValueMergeUtil { } /** - * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. + * Performs an actual inlining, thereby replacing the given invoke with the given + * {@code inlineGraph}. * * @param invoke the invoke that will be replaced * @param inlineGraph the graph that the invoke will be replaced with @@ -279,6 +340,23 @@ public class InliningUtil extends ValueMergeUtil { */ @SuppressWarnings("try") public static UnmodifiableEconomicMap inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) { + return inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod, "", ""); + } + + /** + * Performs an actual inlining, thereby replacing the given invoke with the given + * {@code inlineGraph}. + * + * @param invoke the invoke that will be replaced + * @param inlineGraph the graph that the invoke will be replaced with + * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, + * false if no such check is required + * @param inlineeMethod the actual method being inlined. Maybe be null for snippets. + * @param reason the reason for inlining, used in tracing + * @param phase the phase that invoked inlining + */ + @SuppressWarnings("try") + public static UnmodifiableEconomicMap inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, String reason, String phase) { FixedNode invokeNode = invoke.asNode(); StructuredGraph graph = invokeNode.graph(); final NodeInputList parameters = invoke.callTarget().arguments(); @@ -339,7 +417,15 @@ public class InliningUtil extends ValueMergeUtil { assert invokeNode.successors().first() != null : invoke; assert invokeNode.predecessor() != null; - EconomicMap duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement); + Mark mark = graph.getMark(); + // Instead, attach the inlining log of the child graph to the current inlining log. + EconomicMap duplicates; + try (InliningLog.UpdateScope scope = graph.getInliningLog().openDefaultUpdateScope()) { + duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement); + if (scope != null) { + graph.getInliningLog().addDecision(invoke, true, reason, phase, duplicates, inlineGraph.getInliningLog()); + } + } FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); @@ -353,7 +439,7 @@ public class InliningUtil extends ValueMergeUtil { } } - updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod)); + updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod), mark); if (stateAfter != null) { processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1); int callerLockDepth = stateAfter.nestedLockDepth(); @@ -409,9 +495,14 @@ public class InliningUtil extends ValueMergeUtil { return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, null); } - @SuppressWarnings("try") public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, Consumer> duplicatesConsumer) { + return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, duplicatesConsumer, "", ""); + } + + @SuppressWarnings("try") + public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, + Consumer> duplicatesConsumer, String reason, String phase) { HashSetNodeEventListener listener = new HashSetNodeEventListener(); /* * This code relies on the fact that Graph.addDuplicates doesn't trigger the @@ -419,7 +510,7 @@ public class InliningUtil extends ValueMergeUtil { * the graph into the current graph. */ try (NodeEventScope nes = invoke.asNode().graph().trackNodeEvents(listener)) { - UnmodifiableEconomicMap duplicates = InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod); + UnmodifiableEconomicMap duplicates = InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod, reason, phase); if (duplicatesConsumer != null) { duplicatesConsumer.accept(duplicates); } @@ -462,7 +553,7 @@ public class InliningUtil extends ValueMergeUtil { } } else { if (unwindNode != null && unwindNode.isAlive()) { - DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler); unwindNode.replaceAndDelete(deoptimizeNode); } } @@ -571,27 +662,47 @@ public class InliningUtil extends ValueMergeUtil { } @SuppressWarnings("try") - private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap duplicates, boolean isSubstitution) { - if (inlineGraph.mayHaveNodeSourcePosition() && invoke.stateAfter() != null) { - if (invoke.asNode().getNodeSourcePosition() == null) { - // Temporarily ignore the assert below. - return; + private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap duplicates, boolean isSub, Mark mark) { + FixedNode invokeNode = invoke.asNode(); + boolean isSubstitution = isSub || inlineGraph.method().getAnnotation(MethodSubstitution.class) != null || inlineGraph.method().getAnnotation(Snippet.class) != null; + StructuredGraph invokeGraph = invokeNode.graph(); + assert !invokeGraph.trackNodeSourcePosition() || inlineGraph.trackNodeSourcePosition() || + isSubstitution : String.format("trackNodeSourcePosition mismatch %s %s != %s %s", invokeGraph, invokeGraph.trackNodeSourcePosition(), inlineGraph, + inlineGraph.trackNodeSourcePosition()); + if (invokeGraph.trackNodeSourcePosition() && invoke.stateAfter() != null) { + final NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition(); + updateSourcePosition(invokeGraph, duplicates, mark, invokePos, isSubstitution); + } + } + + public static void updateSourcePosition(StructuredGraph invokeGraph, UnmodifiableEconomicMap duplicates, Mark mark, NodeSourcePosition invokePos, boolean isSubstitution) { + /* + * Not every duplicate node is newly created, so only update the position of the newly + * created nodes. + */ + EconomicSet newNodes = EconomicSet.create(Equivalence.DEFAULT); + newNodes.addAll(invokeGraph.getNewNodes(mark)); + EconomicMap posMap = EconomicMap.create(Equivalence.DEFAULT); + UnmodifiableMapCursor cursor = duplicates.getEntries(); + while (cursor.advance()) { + if (!newNodes.contains(cursor.getValue())) { + continue; } - - JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() && !isSubstitution ? invoke.getReceiver().asJavaConstant() : null; - NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition(); - assert invokePos != null : "missing source information"; - - EconomicMap posMap = EconomicMap.create(Equivalence.DEFAULT); - UnmodifiableMapCursor cursor = duplicates.getEntries(); - while (cursor.advance()) { - NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition(); - if (pos != null) { - NodeSourcePosition callerPos = pos.addCaller(constantReceiver, invokePos); - if (!posMap.containsKey(callerPos)) { - posMap.put(callerPos, callerPos); - } - cursor.getValue().setNodeSourcePosition(posMap.get(callerPos)); + NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition(); + if (pos != null) { + NodeSourcePosition callerPos = posMap.get(pos); + if (callerPos == null) { + callerPos = pos.addCaller(invokePos, isSubstitution); + posMap.put(pos, callerPos); + } + cursor.getValue().setNodeSourcePosition(callerPos); + } else { + if (isSubstitution) { + /* + * If no other position is provided at least attribute the substituted node to + * the original invoke. + */ + cursor.getValue().setNodeSourcePosition(invokePos); } } } @@ -642,7 +753,15 @@ public class InliningUtil extends ValueMergeUtil { } frameState.replaceAndDelete(stateAfterException); return stateAfterException; - } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + } else if ((frameState.bci == BytecodeFrame.UNWIND_BCI && frameState.graph().getGuardsStage() == GuardsStage.FLOATING_GUARDS) || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + /* + * This path converts the frame states relevant for exception unwinding to + * deoptimization. This is only allowed in configurations when Graal compiles code for + * speculative execution (e.g., JIT compilation in HotSpot) but not when compiled code + * must be deoptimization free (e.g., AOT compilation for native image generation). + * There is currently no global flag in StructuredGraph to distinguish such modes, but + * the GuardsStage during inlining indicates the mode in which Graal operates. + */ handleMissingAfterExceptionFrameState(frameState, invoke, replacements, alwaysDuplicateStateAfter); return frameState; } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { @@ -706,7 +825,6 @@ public class InliningUtil extends ValueMergeUtil { assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) { ResolvedJavaMethod method = frameState.getMethod(); if (method.equals(inlinedMethod)) { @@ -738,7 +856,7 @@ public class InliningUtil extends ValueMergeUtil { } public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState, Invoke invoke, EconomicMap replacements, boolean alwaysDuplicateStateAfter) { - Graph graph = nonReplaceableFrameState.graph(); + StructuredGraph graph = nonReplaceableFrameState.graph(); NodeWorkList workList = graph.createNodeWorkList(); workList.add(nonReplaceableFrameState); for (Node node : workList) { @@ -756,7 +874,7 @@ public class InliningUtil extends ValueMergeUtil { AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit; while (merge.isAlive()) { AbstractEndNode end = merge.forwardEnds().first(); - DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler); end.replaceAtPredecessor(deoptimizeNode); GraphUtil.killCFG(end); } @@ -775,7 +893,7 @@ public class InliningUtil extends ValueMergeUtil { } handleAfterBciFrameState(newInvoke.stateAfter(), invoke, alwaysDuplicateStateAfter); } else { - FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + FixedNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler); if (fixedStateSplit instanceof AbstractBeginNode) { deoptimizeNode = BeginNode.begin(deoptimizeNode); } @@ -788,6 +906,11 @@ public class InliningUtil extends ValueMergeUtil { return nonReplaceableFrameState; } + private static DeoptimizeNode addDeoptimizeNode(StructuredGraph graph, DeoptimizationAction action, DeoptimizationReason reason) { + GraalError.guarantee(graph.getGuardsStage() == GuardsStage.FLOATING_GUARDS, "Cannot introduce speculative deoptimization when Graal is used with fixed guards"); + return graph.add(new DeoptimizeNode(action, reason)); + } + /** * Ensure that all states are either {@link BytecodeFrame#INVALID_FRAMESTATE_BCI} or one of * {@link BytecodeFrame#AFTER_BCI} or {@link BytecodeFrame#BEFORE_BCI}. Mixing of before and @@ -856,8 +979,8 @@ public class InliningUtil extends ValueMergeUtil { return replacements.hasSubstitution(target, invokeBci); } - public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci) { - return replacements.getSubstitution(target, invokeBci); + public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { + return replacements.getSubstitution(target, invokeBci, trackNodeSourcePosition, replaceePosition); } public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class macroNodeClass) throws GraalError { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java index fe675d91193..5aa39e04f52 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java @@ -64,7 +64,7 @@ public abstract class AbstractInlineInfo implements InlineInfo { @SuppressWarnings("try") public final void populateInlinableElements(HighTierContext context, StructuredGraph caller, CanonicalizerPhase canonicalizer, OptionValues options) { for (int i = 0; i < numberOfMethods(); i++) { - Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context, canonicalizer); + Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context, canonicalizer, caller.trackNodeSourcePosition()); setInlinableElement(i, elem); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java index 2bdeb86117f..12b45b95849 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java @@ -30,10 +30,10 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public interface Inlineable { - static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) { + static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer, boolean trackNodeSourcePosition) { assert method != null; assert invoke != null; - return new InlineableGraph(method, invoke, context, canonicalizer); + return new InlineableGraph(method, invoke, context, canonicalizer, trackNodeSourcePosition); } int getNodeCount(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java index 317a0556b58..2a7425f30fe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java @@ -66,8 +66,8 @@ public class InlineableGraph implements Inlineable { private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache(); - public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) { - StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci()); + public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer, boolean trackNodeSourcePosition) { + StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci(), trackNodeSourcePosition); // TODO copying the graph is only necessary if it is modified or if it contains any invokes this.graph = (StructuredGraph) original.copy(invoke.asNode().getDebug()); specializeGraphToArguments(invoke, context, canonicalizer); @@ -78,12 +78,13 @@ public class InlineableGraph implements Inlineable { * The graph thus obtained is returned, ie the caller is responsible for cloning before * modification. */ - private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci) { - StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci); + private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci, + boolean trackNodeSourcePosition) { + StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci, trackNodeSourcePosition, null); if (result != null) { return result; } - return parseBytecodes(method, context, canonicalizer, caller); + return parseBytecodes(method, context, canonicalizer, caller, trackNodeSourcePosition); } /** @@ -193,9 +194,10 @@ public class InlineableGraph implements Inlineable { *

    */ @SuppressWarnings("try") - private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) { + private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, boolean trackNodeSourcePosition) { DebugContext debug = caller.getDebug(); - StructuredGraph newGraph = new StructuredGraph.Builder(caller.getOptions(), debug, AllowAssumptions.ifNonNull(caller.getAssumptions())).method(method).build(); + StructuredGraph newGraph = new StructuredGraph.Builder(caller.getOptions(), debug, AllowAssumptions.ifNonNull(caller.getAssumptions())).method(method).trackNodeSourcePosition( + trackNodeSourcePosition).build(); try (DebugContext.Scope s = debug.scope("InlineGraph", newGraph)) { if (!caller.isUnsafeAccessTrackingEnabled()) { newGraph.disableUnsafeAccessTracking(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java index 0976740f586..d49985e394a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java @@ -69,17 +69,17 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { final double relevance = invocation.relevance(); if (InlineEverything.getValue(options)) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); return true; } if (isIntrinsic(replacements, info)) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); return true; } if (info.shouldInline()) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); return true; } @@ -88,13 +88,13 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { int lowLevelGraphSize = previousLowLevelGraphSize(info); if (SmallCompiledLowLevelGraphSize.getValue(options) > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue(options) * inliningBonus) { - InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize, + InliningUtil.traceNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize, relevance, probability, inliningBonus, nodes); return false; } if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); return true; } @@ -106,19 +106,19 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { */ double invokes = determineInvokeProbability(info); if (LimitInlinedInvokes.getValue(options) > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue(options) * inliningBonus) { - InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance, + InliningUtil.traceNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance, probability, inliningBonus, nodes); return false; } double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue(options) * inliningBonus)); if (nodes <= maximumNodes) { - InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, + InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, nodes, maximumNodes); return true; } - InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); + InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); return false; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java index 9b03288dcdc..0af953c9acb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java @@ -39,7 +39,7 @@ public final class InlineMethodSubstitutionsPolicy extends InlineEverythingPolic CallTargetNode callTarget = invocation.callee().invoke().callTarget(); if (callTarget instanceof MethodCallTargetNode) { ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod(); - if (replacements.getSubstitution(calleeMethod, invocation.callee().invoke().bci()) != null) { + if (replacements.hasSubstitution(calleeMethod, invocation.callee().invoke().bci())) { return true; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java index f74fc8449ff..2411202e9ee 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java @@ -166,7 +166,7 @@ public class InliningData { if (failureMessage == null) { return true; } else { - InliningUtil.logNotInlined(invoke, inliningDepth(), method, failureMessage); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), method, failureMessage); return false; } } @@ -257,13 +257,13 @@ public class InliningData { private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) { JavaTypeProfile typeProfile = ((MethodCallTargetNode) invoke.callTarget()).getProfile(); if (typeProfile == null) { - InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no type profile exists"); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no type profile exists"); return null; } JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes(); if (ptypes == null || ptypes.length <= 0) { - InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no types in profile"); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types in profile"); return null; } ResolvedJavaType contextType = invoke.getContextType(); @@ -272,7 +272,7 @@ public class InliningData { OptionValues options = invoke.asNode().getOptions(); if (ptypes.length == 1 && notRecordedTypeProbability == 0) { if (!optimisticOpts.inlineMonomorphicCalls(options)) { - InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled"); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled"); return null; } @@ -287,13 +287,13 @@ public class InliningData { invoke.setPolymorphic(true); if (!optimisticOpts.inlinePolymorphicCalls(options) && notRecordedTypeProbability == 0) { - InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); return null; } if (!optimisticOpts.inlineMegamorphicCalls(options) && notRecordedTypeProbability > 0) { // due to filtering impossible types, notRecordedTypeProbability can be > 0 although // the number of types is lower than what can be recorded in a type profile - InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100); return null; } @@ -304,7 +304,7 @@ public class InliningData { for (int i = 0; i < ptypes.length; i++) { ResolvedJavaMethod concrete = ptypes[i].getType().resolveConcreteMethod(targetMethod, contextType); if (concrete == null) { - InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "could not resolve method"); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "could not resolve method"); return null; } int index = concreteMethods.indexOf(concrete); @@ -331,7 +331,7 @@ public class InliningData { if (newConcreteMethods.isEmpty()) { // No method left that is worth inlining. - InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size()); return null; } @@ -341,7 +341,7 @@ public class InliningData { } if (concreteMethods.size() > maxMethodPerInlining) { - InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining); return null; } @@ -362,13 +362,13 @@ public class InliningData { if (usedTypes.isEmpty()) { // No type left that is worth checking for. - InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); return null; } for (ResolvedJavaMethod concrete : concreteMethods) { if (!checkTargetConditions(invoke, concrete)) { - InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); + InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); return null; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java index 24c664d5b00..6a64d6924e4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java @@ -95,6 +95,13 @@ public class PhaseSuite extends BasePhase { return it; } + /** + * Gets an unmodifiable view on the phases in this suite. + */ + public List> getPhases() { + return Collections.unmodifiableList(phases); + } + /** * Returns a {@link ListIterator} at the position of the first phase which is an instance of * {@code phaseClass} or null if no such phase can be found. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java index 0047dc97027..fec3f7e7807 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.phases.contract; -import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.function.Predicate; @@ -64,13 +63,8 @@ public class VerifyNodeCosts { } private static NodeClass getType(Class c) { - Field f; try { - f = c.getField("TYPE"); - f.setAccessible(true); - Object val = f.get(null); - NodeClass nodeType = (NodeClass) val; - return nodeType; + return NodeClass.get(c); } catch (Throwable t) { throw new VerifyPhase.VerificationError("%s.java does not specify a TYPE field.", c.getName()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java index d5dc2508341..f51bb7f74c3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java @@ -46,6 +46,7 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeMap; import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.graph.SourceLanguagePosition; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -67,9 +68,9 @@ import org.graalvm.graphio.GraphOutput; import org.graalvm.graphio.GraphStructure; import org.graalvm.graphio.GraphTypes; +import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; public class BinaryGraphPrinter implements @@ -265,6 +266,17 @@ public class BinaryGraphPrinter implements } props.put("category", "floating"); } + if (node.getNodeSourcePosition() != null) { + NodeSourcePosition pos = node.getNodeSourcePosition(); + while (pos != null) { + SourceLanguagePosition cur = pos.getSourceLanauage(); + if (cur != null) { + cur.addSourceInformation(props); + break; + } + pos = pos.getCaller(); + } + } if (getSnippetReflectionProvider() != null) { for (Map.Entry prop : props.entrySet()) { if (prop.getValue() instanceof JavaConstantFormattable) { @@ -380,8 +392,8 @@ public class BinaryGraphPrinter implements if (obj instanceof Class) { return ((Class) obj).getName(); } - if (obj instanceof ResolvedJavaType) { - return ((ResolvedJavaType) obj).toJavaName(); + if (obj instanceof JavaType) { + return ((JavaType) obj).toJavaName(); } return null; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java index 7cb7b9dc0ec..5540cb4784c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java @@ -79,7 +79,7 @@ interface GraphPrinter extends Closeable, JavaConstantFormatter { /** * {@code jdk.vm.ci} module. */ - Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule.invoke(Services.class); + Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule(Services.class); /** * Classes whose {@link #toString()} method does not run any untrusted code. @@ -111,8 +111,8 @@ interface GraphPrinter extends Closeable, JavaConstantFormatter { return true; } } else { - Object module = JDK9Method.getModule.invoke(c); - if (JVMCI_MODULE == module || (Boolean) JDK9Method.isOpenTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) { + Object module = JDK9Method.getModule(c); + if (JVMCI_MODULE == module || JDK9Method.isOpenTo(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) { // Can access non-statically-exported package in JVMCI return true; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java index a875ca30b01..9b6f38b9f28 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java @@ -244,7 +244,10 @@ public class GraphPrinterDumpHandler implements DebugDumpHandler { lastMethodOrGraph = o; } } - + if (result.size() == 2 && result.get(1).startsWith("TruffleGraal")) { + result.clear(); + result.add("Graal Graphs"); + } if (result.isEmpty()) { result.add(graph.toString()); graphSeen = true; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java index ad5dbccd87f..fdf9ce335b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java @@ -75,7 +75,7 @@ public class AArch64FloatArithmeticSnippets extends SnippetTemplate.AbstractTemp Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); args.add("x", node.getX()); args.add("y", node.getY()); - template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args); + template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args); } @Snippet diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java index cf6ba186a14..fab0c95b68c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java @@ -106,7 +106,7 @@ public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implemen Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); args.add("x", node.getX()); args.add("y", node.getY()); - template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); + template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); } @Snippet diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java index d07bcfbc6d7..cee82b8d1e1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java @@ -189,7 +189,7 @@ public class AMD64ConvertSnippets implements Snippets { args.add("input", convert.getValue()); args.add("result", graph.unique(new AMD64FloatConvertNode(convert.getFloatConvert(), convert.getValue()))); - SnippetTemplate template = template(convert.getDebug(), args); + SnippetTemplate template = template(convert, args); convert.getDebug().log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args); template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args); convert.safeDelete(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index 0cffd5ae3bf..c2cb77fbee9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -29,6 +29,7 @@ import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.Una import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static org.graalvm.compiler.serviceprovider.JDK9Method.JAVA_SPECIFICATION_VERSION; import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; import java.util.Arrays; @@ -75,6 +76,8 @@ public class AMD64GraphBuilderPlugins { registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch, replacementsBytecodeProvider); registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider); registerStringPlugins(invocationPlugins, arch, replacementsBytecodeProvider); + registerStringLatin1Plugins(invocationPlugins, replacementsBytecodeProvider); + registerStringUTF16Plugins(invocationPlugins, replacementsBytecodeProvider); registerMathPlugins(invocationPlugins, arch, arithmeticStubs, replacementsBytecodeProvider); registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider); } @@ -183,12 +186,34 @@ public class AMD64GraphBuilderPlugins { } private static void registerStringPlugins(InvocationPlugins plugins, AMD64 arch, BytecodeProvider replacementsBytecodeProvider) { - if (Java8OrEarlier && arch.getFeatures().contains(CPUFeature.SSE4_2)) { + if (Java8OrEarlier) { Registration r; r = new Registration(plugins, String.class, replacementsBytecodeProvider); r.setAllowOverwrite(true); - r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class, - int.class, char[].class, int.class, int.class, int.class); + if (arch.getFeatures().contains(CPUFeature.SSE4_2)) { + r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class, + int.class, char[].class, int.class, int.class, int.class); + } + // r.registerMethodSubstitution(AMD64StringSubstitutions.class, "compareTo", + // Receiver.class, String.class); + } + } + + private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { + if (JAVA_SPECIFICATION_VERSION >= 9) { + Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider); + r.setAllowOverwrite(true); + r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class); + r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class); + } + } + + private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { + if (JAVA_SPECIFICATION_VERSION >= 9) { + Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider); + r.setAllowOverwrite(true); + r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class); + r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java new file mode 100644 index 00000000000..52c9d1db8ff --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.replacements.amd64; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; + +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@code java.lang.StringLatin1} methods. + * + * Since JDK 9. + */ +@ClassSubstitution(className = "java.lang.StringLatin1", optional = true) +public class AMD64StringLatin1Substitutions { + + /** + * @param value is byte[] + * @param other is byte[] + */ + @MethodSubstitution + public static int compareTo(byte[] value, byte[] other) { + return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Byte); + } + + /** + * @param value is byte[] + * @param other is char[] + */ + @MethodSubstitution + public static int compareToUTF16(byte[] value, byte[] other) { + return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Char); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java index 0524356c185..9265db87a57 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java @@ -26,8 +26,11 @@ import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.replacements.StringSubstitutions; +import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; import org.graalvm.compiler.word.Word; import org.graalvm.word.Pointer; @@ -86,4 +89,16 @@ public class AMD64StringSubstitutions { } return result; } + + @MethodSubstitution(isStatic = false) + @SuppressFBWarnings(value = "ES_COMPARING_PARAMETER_STRING_WITH_EQ", justification = "reference equality on the receiver is what we want") + public static int compareTo(String receiver, String anotherString) { + if (receiver == anotherString) { + return 0; + } + char[] value = StringSubstitutions.getValue(receiver); + char[] other = StringSubstitutions.getValue(anotherString); + return ArrayCompareToNode.compareTo(value, other, value.length << 1, other.length << 1, JavaKind.Char, JavaKind.Char); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java new file mode 100644 index 00000000000..e2e347918f9 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.replacements.amd64; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; + +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@code java.lang.StringUTF16} methods. + * + * Since JDK 9. + */ +@ClassSubstitution(className = "java.lang.StringUTF16", optional = true) +public class AMD64StringUTF16Substitutions { + + /** + * @param value is char[] + * @param other is char[] + */ + @MethodSubstitution + public static int compareTo(byte[] value, byte[] other) { + return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Char, JavaKind.Char); + } + + /** + * @param value is char[] + * @param other is byte[] + */ + @MethodSubstitution + public static int compareToLatin1(byte[] value, byte[] other) { + /* + * Swapping array arguments because intrinsic expects order to be byte[]/char[] but kind + * arguments stay in original order. + */ + return ArrayCompareToNode.compareTo(other, value, other.length, value.length, JavaKind.Char, JavaKind.Byte); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java index f99d7adb323..7d3eedce2f8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java @@ -109,7 +109,7 @@ public abstract class MethodSubstitutionTest extends GraalCompilerTest { StructuredGraph graph = testGraph(testMethodName); // Check to see if the resulting graph contains the expected node - StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1); + StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1, false, null); if (replacement == null && !optional) { assertInGraph(graph, intrinsicClass); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java index 5fea8c8792a..519a7e23fcd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java @@ -136,9 +136,9 @@ public class PEGraphDecoderTest extends GraalCompilerTest { registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins()); targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build(); CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, - null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null); + null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null, null); - decoder.decode(testMethod); + decoder.decode(testMethod, false); debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph"); targetGraph.verify(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java index 83f9949f3be..a2a7da369dd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java @@ -43,6 +43,6 @@ public abstract class SnippetsTest extends ReplacementsTest { @Override protected StructuredGraph parse(Builder builder, PhaseSuite graphBuilderSuite) { - return installer.makeGraph(getDebugContext(), bytecodeProvider, builder.getMethod(), null, null); + return installer.makeGraph(getDebugContext(), bytecodeProvider, builder.getMethod(), null, null, false, null); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java index 3decde127de..bb556d564a4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java @@ -24,8 +24,6 @@ package org.graalvm.compiler.replacements.test; import java.util.HashMap; -import org.junit.Test; - import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.StructuredGraph; @@ -35,6 +33,7 @@ import org.graalvm.compiler.replacements.nodes.BitCountNode; import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; import org.graalvm.compiler.replacements.nodes.ReverseBytesNode; +import org.junit.Test; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -137,7 +136,7 @@ public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest { StructuredGraph graph = testGraph(testMethodName); // Check to see if the resulting graph contains the expected node - StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1); + StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1, false, null); if (replacement == null && !optional) { assertInGraph(graph, intrinsicClass); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java new file mode 100644 index 00000000000..53f0901c718 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 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. + * + * 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.replacements.test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Ignore; +import org.junit.Test; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests compareTo method intrinsic. + */ +public class StringCompareToTest extends MethodSubstitutionTest { + + private ResolvedJavaMethod realMethod = null; + private ResolvedJavaMethod testMethod = null; + private InstalledCode testCode = null; + + private final String[] testData = new String[]{ + "A", "\uFF21", "AB", "A", "a", "Ab", "AA", "\uFF21", + "A\uFF21", "ABC", "AB", "ABcD", "ABCD\uFF21\uFF21", "ABCD\uFF21", "ABCDEFG\uFF21", "ABCD", + "ABCDEFGH\uFF21\uFF21", "\uFF22", "\uFF21\uFF22", "\uFF21A", + "\uFF21\uFF21", + "\u043c\u0430\u043c\u0430\u0020\u043c\u044b\u043b\u0430\u0020\u0440\u0430\u043c\u0443\u002c\u0020\u0440\u0430\u043c\u0430\u0020\u0441\u044a\u0435\u043b\u0430\u0020\u043c\u0430\u043c\u0443", + "crazy dog jumps over laszy fox", + "XMM-XMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-", + "XMM-XMM+YMM-YMM-ZMM-ZMM-ZMM-ZMM-", + "XMM-XMM-YMM-YMM+ZMM-ZMM-ZMM-ZMM-", + "XMM-XMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM+", + "XMM-XMM-XMM-XMM-YMM-YMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-", + "XMM-XMM-XMM-XMM+YMM-YMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-", + "XMM-XMM-XMM-XMM-YMM-YMM-YMM-YMM+ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-", + "XMM-XMM-XMM-XMM-YMM-YMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM+", + "" + }; + + public StringCompareToTest() { + Assume.assumeTrue(getTarget().arch instanceof AMD64); + + realMethod = getResolvedJavaMethod(String.class, "compareTo", String.class); + testMethod = getResolvedJavaMethod("stringCompareTo"); + StructuredGraph graph = testGraph("stringCompareTo"); + + // Check to see if the resulting graph contains the expected node + StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1, false, null); + if (replacement == null) { + assertInGraph(graph, ArrayCompareToNode.class); + } + + // Force compilation + testCode = getCode(testMethod); + Assert.assertNotNull(testCode); + } + + private void executeStringCompareTo(String s0, String s1) { + Object expected = invokeSafe(realMethod, s0, s1); + // Verify that the original method and the substitution produce the same value + assertDeepEquals(expected, invokeSafe(testMethod, null, s0, s1)); + // Verify that the generated code and the original produce the same value + assertDeepEquals(expected, executeVarargsSafe(testCode, s0, s1)); + } + + public static int stringCompareTo(String a, String b) { + return a.compareTo(b); + } + + @Test + @Ignore("GR-8748") + public void testEqualString() { + String s = "equal-string"; + executeStringCompareTo(s, new String(s.toCharArray())); + } + + @Test + @Ignore("GR-8748") + public void testDifferentString() { + executeStringCompareTo("some-string", "different-string"); + } + + @Test + @Ignore("GR-8748") + public void testAllStrings() { + for (String s0 : testData) { + for (String s1 : testData) { + executeStringCompareTo(s0, s1); + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java index 7c870fa0e32..a6ffa54a6ae 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java @@ -22,11 +22,10 @@ */ package org.graalvm.compiler.replacements.test; -import org.junit.Test; - import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.replacements.StringSubstitutions; import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode; +import org.junit.Test; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -42,7 +41,7 @@ public class StringSubstitutionsTest extends MethodSubstitutionTest { StructuredGraph graph = testGraph(testMethodName); // Check to see if the resulting graph contains the expected node - StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1); + StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1, false, null); if (replacement == null && !optional) { assertInGraph(graph, intrinsicClass); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java index bc788a4dc98..6d463ca3e47 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java @@ -44,7 +44,7 @@ public class WordTest extends SnippetsTest { protected StructuredGraph parse(Builder builder, PhaseSuite graphBuilderSuite) { // create a copy to assign a valid compilation id DebugContext debug = getDebugContext(); - StructuredGraph originalGraph = installer.makeGraph(debug, bytecodeProvider, builder.getMethod(), null, null); + StructuredGraph originalGraph = installer.makeGraph(debug, bytecodeProvider, builder.getMethod(), null, null, false, null); return originalGraph.copyWithIdentifier(builder.getCompilationId(), debug); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java index 63e401302a0..23ac28e0672 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java @@ -29,8 +29,8 @@ import java.util.EnumMap; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; -import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.ValueNode; @@ -207,7 +207,7 @@ public class BoxingSnippets implements Snippets { args.add("value", box.getValue()); args.addConst("valueOfCounter", valueOfCounter); - SnippetTemplate template = template(box.getDebug(), args); + SnippetTemplate template = template(box, args); box.getDebug().log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", box.graph(), box, template, args); template.instantiate(providers.getMetaAccess(), box, DEFAULT_REPLACER, args); } @@ -218,7 +218,7 @@ public class BoxingSnippets implements Snippets { args.add("value", unbox.getValue()); args.addConst("valueCounter", valueCounter); - SnippetTemplate template = template(unbox.getDebug(), args); + SnippetTemplate template = template(unbox, args); unbox.getDebug().log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args); template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, args); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java index 57131df9922..1071d271c56 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java @@ -27,6 +27,7 @@ import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.Compi import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.SourceLanguagePositionProvider; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.nodes.EncodedGraph; import org.graalvm.compiler.nodes.GraphEncoder; @@ -63,9 +64,9 @@ public class CachingPEGraphDecoder extends PEGraphDecoder { public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) { + NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) { super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin, - invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod); + invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod, sourceLanguagePositionProvider); this.providers = providers; this.graphBuilderConfig = graphBuilderConfig; @@ -80,10 +81,11 @@ public class CachingPEGraphDecoder extends PEGraphDecoder { } @SuppressWarnings("try") - private EncodedGraph createGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) { - StructuredGraph graphToEncode = new StructuredGraph.Builder(options, debug, allowAssumptions).useProfilingInfo(false).method(method).build(); + private EncodedGraph createGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider) { + StructuredGraph graphToEncode = new StructuredGraph.Builder(options, debug, allowAssumptions).useProfilingInfo(false).trackNodeSourcePosition( + graphBuilderConfig.trackNodeSourcePosition()).method(method).build(); try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) { - IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(method, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null; + IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(originalMethod, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null; GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext); graphBuilderPhaseInstance.apply(graphToEncode); @@ -106,10 +108,10 @@ public class CachingPEGraphDecoder extends PEGraphDecoder { } @Override - protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) { + protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider, boolean trackNodeSourcePosition) { EncodedGraph result = graphCache.get(method); if (result == null && method.hasBytecodes()) { - result = createGraph(method, intrinsicBytecodeProvider); + result = createGraph(method, originalMethod, intrinsicBytecodeProvider); } return result; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java index eb2b260db00..1577e543c8a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java @@ -65,7 +65,7 @@ public class ConstantStringIndexOfSnippets implements Snippets { char[] targetCharArray = snippetReflection.asObject(char[].class, stringIndexOf.getArgument(3).asJavaConstant()); args.addConst("md2", md2(targetCharArray)); args.addConst("cache", computeCache(targetCharArray)); - template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), stringIndexOf, DEFAULT_REPLACER, args); + template(stringIndexOf, args).instantiate(providers.getMetaAccess(), stringIndexOf, DEFAULT_REPLACER, args); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java index 6ccd8d4f91d..7617143bb1e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java @@ -32,9 +32,11 @@ import java.util.List; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node.ValueNumberable; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.java.FrameStateBuilder; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -52,6 +54,7 @@ import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.UnwindNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -224,28 +227,42 @@ public class GraphKit implements GraphBuilderTool { * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of * arguments. */ + @SuppressWarnings("try") public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { - assert method.isStatic() == (invokeKind == InvokeKind.Static); - Signature signature = method.getSignature(); - JavaType returnType = signature.getReturnType(null); - assert checkArgs(method, args); - StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false); - if (returnStamp == null) { - returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); - } - MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, bci)); - InvokeNode invoke = append(new InvokeNode(callTarget, bci)); + try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.placeholder(method))) { + assert method.isStatic() == (invokeKind == InvokeKind.Static); + Signature signature = method.getSignature(); + JavaType returnType = signature.getReturnType(null); + assert checkArgs(method, args); + StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false); + if (returnStamp == null) { + returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); + } + MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, bci)); + InvokeNode invoke = append(new InvokeNode(callTarget, bci)); - if (frameStateBuilder != null) { - if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.push(invoke.getStackKind(), invoke); - } - invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); - if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.pop(invoke.getStackKind()); + if (frameStateBuilder != null) { + if (invoke.getStackKind() != JavaKind.Void) { + frameStateBuilder.push(invoke.getStackKind(), invoke); + } + invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); + if (invoke.getStackKind() != JavaKind.Void) { + frameStateBuilder.pop(invoke.getStackKind()); + } } + return invoke; } - return invoke; + } + + public InvokeWithExceptionNode createInvokeWithExceptionAndUnwind(ResolvedJavaMethod method, InvokeKind invokeKind, + FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci, ValueNode... args) { + + InvokeWithExceptionNode result = startInvokeWithException(method, invokeKind, frameStateBuilder, invokeBci, exceptionEdgeBci, args); + exceptionPart(); + ExceptionObjectNode exception = exceptionObject(); + append(new UnwindNode(exception)); + endInvokeWithException(); + return result; } protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, @SuppressWarnings("unused") int bci) { @@ -311,6 +328,9 @@ public class GraphKit implements GraphBuilderTool { GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); StructuredGraph calleeGraph = new StructuredGraph.Builder(invoke.getOptions(), invoke.getDebug()).method(method).build(); + if (invoke.graph().trackNodeSourcePosition()) { + calleeGraph.setTrackNodeSourcePosition(); + } IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING); GraphBuilderPhase.Instance instance = new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, OptimisticOptimizations.NONE, @@ -357,11 +377,12 @@ public class GraphKit implements GraphBuilderTool { * * @param condition The condition for the if-block * @param trueProbability The estimated probability the condition is true + * @return the created {@link IfNode}. */ - public void startIf(LogicNode condition, double trueProbability) { + public IfNode startIf(LogicNode condition, double trueProbability) { AbstractBeginNode thenSuccessor = graph.add(new BeginNode()); AbstractBeginNode elseSuccessor = graph.add(new BeginNode()); - append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability)); + IfNode node = append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability)); lastFixedNode = null; IfStructure s = new IfStructure(); @@ -369,6 +390,7 @@ public class GraphKit implements GraphBuilderTool { s.thenPart = thenSuccessor; s.elsePart = elseSuccessor; pushStructure(s); + return node; } private IfStructure saveLastIfNode() { @@ -403,11 +425,18 @@ public class GraphKit implements GraphBuilderTool { s.state = IfState.ELSE_PART; } - public void endIf() { + /** + * Ends an if block started with {@link #startIf(LogicNode, double)}. + * + * @return the created merge node, or {@code null} if no merge node was required (for example, + * when one part ended with a control sink). + */ + public AbstractMergeNode endIf() { IfStructure s = saveLastIfNode(); FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null; FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null; + AbstractMergeNode merge = null; if (thenPart != null && elsePart != null) { /* Both parts are alive, we need a real merge. */ @@ -416,7 +445,7 @@ public class GraphKit implements GraphBuilderTool { EndNode elseEnd = graph.add(new EndNode()); graph.addAfterFixed(elsePart, elseEnd); - AbstractMergeNode merge = graph.add(new MergeNode()); + merge = graph.add(new MergeNode()); merge.addForwardEnd(thenEnd); merge.addForwardEnd(elseEnd); @@ -436,6 +465,7 @@ public class GraphKit implements GraphBuilderTool { } s.state = IfState.FINISHED; popStructure(); + return merge; } static class InvokeWithExceptionStructure extends Structure { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java index 6e62b7addee..3e333301438 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java @@ -26,6 +26,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize; import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsingMaxDepth; import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createStandardInlineInfo; +import org.graalvm.compiler.java.BytecodeParserOptions; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @@ -35,6 +36,15 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public final class InlineDuringParsingPlugin implements InlineInvokePlugin { + /** + * Budget which when exceeded reduces the effective value of + * {@link BytecodeParserOptions#InlineDuringParsingMaxDepth} to + * {@link #MaxDepthAfterBudgetExceeded}. + */ + private static final int NodeBudget = Integer.getInteger("InlineDuringParsingPlugin.NodeBudget", 2000); + + private static final int MaxDepthAfterBudgetExceeded = Integer.getInteger("InlineDuringParsingPlugin.MaxDepthAfterBudgetExceeded", 3); + @Override public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { // @formatter:off @@ -49,7 +59,7 @@ public final class InlineDuringParsingPlugin implements InlineInvokePlugin { if (!method.isSynchronized() && checkSize(method, args, b.getGraph()) && - b.getDepth() < InlineDuringParsingMaxDepth.getValue(b.getOptions())) { + checkInliningDepth(b)) { return createStandardInlineInfo(method); } } @@ -57,6 +67,15 @@ public final class InlineDuringParsingPlugin implements InlineInvokePlugin { return null; } + private static boolean checkInliningDepth(GraphBuilderContext b) { + int nodeCount = b.getGraph().getNodeCount(); + int maxDepth = InlineDuringParsingMaxDepth.getValue(b.getOptions()); + if (nodeCount > NodeBudget && MaxDepthAfterBudgetExceeded < maxDepth) { + maxDepth = MaxDepthAfterBudgetExceeded; + } + return b.getDepth() < maxDepth; + } + private static boolean checkSize(ResolvedJavaMethod method, ValueNode[] args, StructuredGraph graph) { int bonus = 1; for (ValueNode v : args) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java index abc6b32cdec..17ca86bec19 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java @@ -96,7 +96,7 @@ public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates { replacer.replaceUsingInstantiation(); } else { Arguments args = makeArguments(replacer, tool); - template(instanceOf.getDebug(), args).instantiate(providers.getMetaAccess(), instanceOf, replacer, tool, args); + template(instanceOf, args).instantiate(providers.getMetaAccess(), instanceOf, replacer, tool, args); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java index 6e202e96bbb..17909ca0183 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java @@ -31,6 +31,8 @@ import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.FixedNode; @@ -91,6 +93,7 @@ public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver { this.code = code; this.method = code.getMethod(); this.graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(method).build(); + this.graph.setTrackNodeSourcePosition(); this.invokeBci = invokeBci; this.lastInstr = graph.start(); @@ -255,14 +258,18 @@ public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver { return arguments[0]; } + @SuppressWarnings("try") public StructuredGraph buildGraph(InvocationPlugin plugin) { - Receiver receiver = method.isStatic() ? null : this; - if (plugin.execute(this, method, receiver, arguments)) { - assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method; - append(new ReturnNode(returnValue)); - return graph; + NodeSourcePosition position = graph.trackNodeSourcePosition() ? NodeSourcePosition.placeholder(method) : null; + try (DebugCloseable context = graph.withNodeSourcePosition(position)) { + Receiver receiver = method.isStatic() ? null : this; + if (plugin.execute(this, method, receiver, arguments)) { + assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method; + append(new ReturnNode(returnValue)); + return graph; + } + return null; } - return null; } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java index 2c3be468112..2c284bf1b1f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java @@ -48,6 +48,8 @@ import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.graph.SourceLanguagePosition; +import org.graalvm.compiler.graph.SourceLanguagePositionProvider; import org.graalvm.compiler.graph.spi.Canonicalizable; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -108,6 +110,7 @@ import org.graalvm.compiler.phases.common.inlining.InliningUtil; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; @@ -142,7 +145,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)// public static final OptionKey MaximumLoopExplosionCount = new OptionKey<>(10000); - @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) // + @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)// public static final OptionKey FailedLoopExplosionIsFatal = new OptionKey<>(false); } @@ -154,6 +157,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { protected final int inliningDepth; protected final ValueNode[] arguments; + private final SourceLanguagePosition sourceLanguagePosition; protected FrameState outerState; protected FrameState exceptionState; @@ -169,6 +173,13 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { this.invokeData = invokeData; this.inliningDepth = inliningDepth; this.arguments = arguments; + SourceLanguagePosition position = null; + if (arguments != null && method.hasReceiver() && arguments.length > 0 && arguments[0].isJavaConstant()) { + JavaConstant constantArgument = arguments[0].asJavaConstant(); + position = sourceLanguagePositionProvider.getPosition(constantArgument); + } + this.sourceLanguagePosition = position; + } @Override @@ -176,15 +187,24 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { return caller != null; } - public NodeSourcePosition getCallerBytecodePosition() { + @Override + public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) { if (caller == null) { - return null; + return position; } if (callerBytecodePosition == null) { - JavaConstant constantReceiver = caller.invokeData == null ? null : caller.invokeData.constantReceiver; - NodeSourcePosition callerPosition = caller.getCallerBytecodePosition(); NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition(); - callerBytecodePosition = invokePosition != null ? invokePosition.addCaller(constantReceiver, callerPosition) : callerPosition; + if (invokePosition == null) { + assert position == null : "should only happen when tracking is disabled"; + return null; + } + callerBytecodePosition = invokePosition; + } + if (position != null) { + return position.addCaller(caller.sourceLanguagePosition, callerBytecodePosition); + } + if (caller.sourceLanguagePosition != null && callerBytecodePosition != null) { + return new NodeSourcePosition(caller.sourceLanguagePosition, callerBytecodePosition.getCaller(), callerBytecodePosition.getMethod(), callerBytecodePosition.getBCI()); } return callerBytecodePosition; } @@ -361,8 +381,11 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { } private DebugCloseable withNodeSoucePosition() { - if (getGraph().mayHaveNodeSourcePosition()) { - return getGraph().withNodeSourcePosition(methodScope.getCallerBytecodePosition()); + if (getGraph().trackNodeSourcePosition()) { + NodeSourcePosition callerBytecodePosition = methodScope.getCallerBytecodePosition(); + if (callerBytecodePosition != null) { + return getGraph().withNodeSourcePosition(callerBytecodePosition); + } } return null; } @@ -440,11 +463,12 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { private final EconomicMap specialCallTargetCache; private final EconomicMap invocationPluginCache; private final ResolvedJavaMethod callInlinedMethod; + protected final SourceLanguagePositionProvider sourceLanguagePositionProvider; public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) { + NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) { super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true); this.loopExplosionPlugin = loopExplosionPlugin; this.invocationPlugins = invocationPlugins; @@ -454,6 +478,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT); this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT); this.callInlinedMethod = callInlinedMethod; + this.sourceLanguagePositionProvider = sourceLanguagePositionProvider; } protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { @@ -464,8 +489,8 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { } } - public void decode(ResolvedJavaMethod method) { - PEMethodScope methodScope = new PEMethodScope(graph, null, null, lookupEncodedGraph(method, null), method, null, 0, loopExplosionPlugin, null); + public void decode(ResolvedJavaMethod method, boolean trackNodeSourcePosition) { + PEMethodScope methodScope = new PEMethodScope(graph, null, null, lookupEncodedGraph(method, null, null, trackNodeSourcePosition), method, null, 0, loopExplosionPlugin, null); decode(createInitialLoopScope(methodScope, null)); cleanupGraph(methodScope); @@ -533,6 +558,12 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { MethodCallTargetNode methodCall = (MethodCallTargetNode) callTarget; if (methodCall.invokeKind().hasReceiver()) { invokeData.constantReceiver = methodCall.arguments().get(0).asJavaConstant(); + NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition(); + if (invokeData.constantReceiver != null && invokePosition != null) { + // new NodeSourcePosition(invokeData.constantReceiver, + // invokePosition.getCaller(), invokePosition.getMethod(), + // invokePosition.getBCI()); + } } LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget); if (inlineLoopScope != null) { @@ -687,11 +718,12 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, InlineInfo inlineInfo, ValueNode[] arguments) { ResolvedJavaMethod inlineMethod = inlineInfo.getMethodToInline(); - EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.getIntrinsicBytecodeProvider()); + EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.getOriginalMethod(), inlineInfo.getIntrinsicBytecodeProvider(), graph.trackNodeSourcePosition()); if (graphToInline == null) { return null; } + assert !graph.trackNodeSourcePosition() || graphToInline.trackNodeSourcePosition() : graph + " " + graphToInline; if (methodScope.inliningDepth > Options.InliningDepthError.getValue(options)) { throw tooDeepInlining(methodScope); } @@ -740,6 +772,32 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i]; } + // Copy assumptions from inlinee to caller + Assumptions assumptions = graph.getAssumptions(); + Assumptions inlinedAssumptions = graphToInline.getAssumptions(); + if (assumptions != null) { + if (inlinedAssumptions != null) { + assumptions.record(inlinedAssumptions); + } + } else { + assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", inlineMethod, graph); + } + + // Copy inlined methods from inlinee to caller + List inlinedMethods = graphToInline.getInlinedMethods(); + if (inlinedMethods != null) { + graph.getMethods().addAll(inlinedMethods); + } + + if (graphToInline.getFields() != null) { + for (ResolvedJavaField field : graphToInline.getFields()) { + graph.recordField(field); + } + } + if (graphToInline.hasUnsafeAccess()) { + graph.markUnsafeAccess(); + } + /* * Do the actual inlining by returning the initial loop scope for the inlined method scope. */ @@ -927,7 +985,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { } } - protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider); + protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider, boolean trackNodeSourcePosition); @Override protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) { @@ -1123,20 +1181,6 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { } } - @Override - protected Node addFloatingNode(MethodScope s, Node node) { - Node addedNode = super.addFloatingNode(s, node); - PEMethodScope methodScope = (PEMethodScope) s; - NodeSourcePosition pos = node.getNodeSourcePosition(); - if (methodScope.isInlinedMethod()) { - if (pos != null) { - NodeSourcePosition bytecodePosition = methodScope.getCallerBytecodePosition(); - node.setNodeSourcePosition(pos.addCaller(bytecodePosition)); - } - } - return addedNode; - } - @Override protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { PEMethodScope methodScope = (PEMethodScope) s; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java index f034fa3c2bc..45c3b8daed6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java @@ -55,6 +55,7 @@ import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TimerKey; import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.java.GraphBuilderPhase.Instance; @@ -148,7 +149,7 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { if (subst != null) { if (b.parsingIntrinsic() || InlineDuringParsing.getValue(b.getOptions()) || InlineIntrinsicsDuringParsing.getValue(b.getOptions())) { // Forced inlining of intrinsics - return createIntrinsicInlineInfo(subst.getMethod(), subst.getOrigin()); + return createIntrinsicInlineInfo(subst.getMethod(), method, subst.getOrigin()); } return null; } @@ -156,7 +157,7 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; // Force inlining when parsing replacements - return createIntrinsicInlineInfo(method, defaultBytecodeProvider); + return createIntrinsicInlineInfo(method, null, defaultBytecodeProvider); } else { assert method.getAnnotation(NodeIntrinsic.class) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), method.format("%h.%n"), b); @@ -202,8 +203,8 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { private static final TimerKey SnippetPreparationTime = DebugContext.timer("SnippetPreparationTime"); @Override - public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) { - return getSnippet(method, null, args); + public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { + return getSnippet(method, null, args, trackNodeSourcePosition, replaceePosition); } private static final AtomicInteger nextDebugContextId = new AtomicInteger(); @@ -217,29 +218,34 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { @Override @SuppressWarnings("try") - public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args) { + public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName(); assert method.hasBytecodes() : "Snippet must not be abstract or native"; StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(method) : null; - if (graph == null) { + if (graph == null || (trackNodeSourcePosition && !graph.trackNodeSourcePosition())) { try (DebugContext debug = openDebugContext("Snippet_", method); DebugCloseable a = SnippetPreparationTime.start(debug)) { - StructuredGraph newGraph = makeGraph(debug, defaultBytecodeProvider, method, args, recursiveEntry); + StructuredGraph newGraph = makeGraph(debug, defaultBytecodeProvider, method, args, recursiveEntry, trackNodeSourcePosition, replaceePosition); DebugContext.counter("SnippetNodeCount[%#s]", method).add(newGraph.getDebug(), newGraph.getNodeCount()); if (!UseSnippetGraphCache.getValue(options) || args != null) { return newGraph; } newGraph.freeze(); - graphs.putIfAbsent(method, newGraph); + if (graph != null) { + graphs.replace(method, graph, newGraph); + } else { + graphs.putIfAbsent(method, newGraph); + } graph = graphs.get(method); } } + assert !trackNodeSourcePosition || graph.trackNodeSourcePosition(); return graph; } @Override - public void registerSnippet(ResolvedJavaMethod method) { + public void registerSnippet(ResolvedJavaMethod method, boolean trackNodeSourcePosition) { // No initialization needed as snippet graphs are created on demand in getSnippet } @@ -266,7 +272,7 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { } @Override - public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci) { + public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { StructuredGraph result; InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method); if (plugin != null && (!plugin.inlineOnly() || invokeBci >= 0)) { @@ -275,9 +281,9 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin; ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess); StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(substitute) : null; - if (graph == null) { + if (graph == null || graph.trackNodeSourcePosition() != trackNodeSourcePosition) { try (DebugContext debug = openDebugContext("Substitution_", method)) { - graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method); + graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method, trackNodeSourcePosition, replaceePosition); if (!UseSnippetGraphCache.getValue(options)) { return graph; } @@ -311,9 +317,11 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { * @param args * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null + * @param trackNodeSourcePosition */ - public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) { - return createGraphMaker(method, original).makeGraph(debug, bytecodeProvider, args); + public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, boolean trackNodeSourcePosition, + NodeSourcePosition replaceePosition) { + return createGraphMaker(method, original).makeGraph(debug, bytecodeProvider, args, trackNodeSourcePosition, replaceePosition); } /** @@ -350,10 +358,10 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { } @SuppressWarnings("try") - public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, Object[] args) { + public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { try (DebugContext.Scope s = debug.scope("BuildSnippetGraph", method)) { assert method.hasBytecodes() : method; - StructuredGraph graph = buildInitialGraph(debug, bytecodeProvider, method, args); + StructuredGraph graph = buildInitialGraph(debug, bytecodeProvider, method, args, trackNodeSourcePosition, replaceePosition); finalizeGraph(graph); @@ -417,10 +425,12 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { * Builds the initial graph for a replacement. */ @SuppressWarnings("try") - protected StructuredGraph buildInitialGraph(DebugContext debug, BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args) { + protected StructuredGraph buildInitialGraph(DebugContext debug, BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args, boolean trackNodeSourcePosition, + NodeSourcePosition replaceePosition) { // Replacements cannot have optimistic assumptions since they have // to be valid for the entire run of the VM. - final StructuredGraph graph = new StructuredGraph.Builder(replacements.options, debug).method(methodToParse).build(); + final StructuredGraph graph = new StructuredGraph.Builder(replacements.options, debug).method(methodToParse).trackNodeSourcePosition(trackNodeSourcePosition).callerContext( + replaceePosition).build(); // Replacements are not user code so they do not participate in unsafe access // tracking diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java index cdf3c60dbfb..b5fffd62580 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java @@ -156,7 +156,7 @@ public class SnippetCounterNode extends FixedWithNextNode implements Lowerable { args.addConst("counter", counter.getCounter()); args.add("increment", counter.getIncrement()); - template(counter.getDebug(), args).instantiate(providers.getMetaAccess(), counter, DEFAULT_REPLACER, args); + template(counter, args).instantiate(providers.getMetaAccess(), counter, DEFAULT_REPLACER, args); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java index c53b361159d..fa80b3e1b1d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java @@ -47,27 +47,15 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.Local; -import jdk.vm.ci.meta.LocalVariableTable; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; -import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; - import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Equivalence; import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.replacements.Snippet; -import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter; import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -76,14 +64,15 @@ import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.DebugContext.Description; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TimerKey; -import org.graalvm.compiler.debug.DebugContext.Description; +import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.graph.Position; -import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.loop.LoopEx; import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.loop.phases.LoopTransformations; @@ -97,20 +86,21 @@ import org.graalvm.compiler.nodes.DeoptimizingNode; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.InliningLog; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.PiNode.Placeholder; +import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValueNodeUtil; -import org.graalvm.compiler.nodes.PiNode.Placeholder; -import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp; -import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.java.LoadIndexedNode; import org.graalvm.compiler.nodes.java.StoreIndexedNode; @@ -131,10 +121,10 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl; import org.graalvm.compiler.phases.common.GuardLoweringPhase; import org.graalvm.compiler.phases.common.LoweringPhase; import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; -import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl; import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.tiers.PhaseContext; import org.graalvm.compiler.phases.util.Providers; @@ -144,6 +134,18 @@ import org.graalvm.util.CollectionsUtil; import org.graalvm.word.LocationIdentity; import org.graalvm.word.WordBase; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Local; +import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + /** * A snippet template is a graph created by parsing a snippet method and then specialized by binding * constants to the snippet's {@link ConstantParameter} parameters. @@ -565,7 +567,7 @@ public class SnippetTemplate { static class Options { @Option(help = "Use a LRU cache for snippet templates.")// - static final OptionKey UseSnippetTemplateCache = new OptionKey<>(true); + public static final OptionKey UseSnippetTemplateCache = new OptionKey<>(true); @Option(help = "")// static final OptionKey MaxTemplatesPerSnippet = new OptionKey<>(50); @@ -618,7 +620,7 @@ public class SnippetTemplate { assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName(); assert findMethod(declaringClass, methodName, method) == null : "found more than one method named " + methodName + " in " + declaringClass; ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(method); - providers.getReplacements().registerSnippet(javaMethod); + providers.getReplacements().registerSnippet(javaMethod, GraalOptions.TrackNodeSourcePosition.getValue(options)); LocationIdentity[] privateLocations = GraalOptions.SnippetCounters.getValue(options) ? SnippetCounterNode.addSnippetCounters(initialPrivateLocations) : initialPrivateLocations; if (GraalOptions.EagerSnippets.getValue(options)) { return new EagerSnippetInfo(javaMethod, privateLocations); @@ -641,13 +643,15 @@ public class SnippetTemplate { * Gets a template for a given key, creating it first if necessary. */ @SuppressWarnings("try") - protected SnippetTemplate template(DebugContext outer, final Arguments args) { + protected SnippetTemplate template(ValueNode replacee, final Arguments args) { + StructuredGraph graph = replacee.graph(); + DebugContext outer = graph.getDebug(); SnippetTemplate template = Options.UseSnippetTemplateCache.getValue(options) && args.cacheable ? templates.get(args.cacheKey) : null; - if (template == null) { + if (template == null || (graph.trackNodeSourcePosition() && !template.snippet.trackNodeSourcePosition())) { try (DebugContext debug = openDebugContext(outer, args)) { try (DebugCloseable a = SnippetTemplateCreationTime.start(debug); DebugContext.Scope s = debug.scope("SnippetSpecialization", args.info.method)) { SnippetTemplates.increment(debug); - template = new SnippetTemplate(options, debug, providers, snippetReflection, args); + template = new SnippetTemplate(options, debug, providers, snippetReflection, args, graph.trackNodeSourcePosition(), replacee); if (Options.UseSnippetTemplateCache.getValue(options) && args.cacheable) { templates.put(args.cacheKey, template); } @@ -697,12 +701,13 @@ public class SnippetTemplate { * Creates a snippet template. */ @SuppressWarnings("try") - protected SnippetTemplate(OptionValues options, DebugContext debug, final Providers providers, SnippetReflectionProvider snippetReflection, Arguments args) { + protected SnippetTemplate(OptionValues options, DebugContext debug, final Providers providers, SnippetReflectionProvider snippetReflection, Arguments args, boolean trackNodeSourcePosition, + Node replacee) { this.snippetReflection = snippetReflection; this.info = args.info; Object[] constantArgs = getConstantArgs(args); - StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs); + StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs, trackNodeSourcePosition, replacee.getNodeSourcePosition()); ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); @@ -710,8 +715,12 @@ public class SnippetTemplate { PhaseContext phaseContext = new PhaseContext(providers); // Copy snippet graph, replacing constant parameters with given arguments - final StructuredGraph snippetCopy = new StructuredGraph.Builder(options, debug).name(snippetGraph.name).method(snippetGraph.method()).build(); - + final StructuredGraph snippetCopy = new StructuredGraph.Builder(options, debug).name(snippetGraph.name).method(snippetGraph.method()).trackNodeSourcePosition( + snippetGraph.trackNodeSourcePosition()).build(); + assert !GraalOptions.TrackNodeSourcePosition.getValue(options) || snippetCopy.trackNodeSourcePosition(); + if (providers.getCodeCache() != null && providers.getCodeCache().shouldDebugNonSafepoints()) { + snippetCopy.setTrackNodeSourcePosition(); + } try (DebugContext.Scope scope = debug.scope("SpecializeSnippet", snippetCopy)) { if (!snippetGraph.isUnsafeAccessTrackingEnabled()) { snippetCopy.disableUnsafeAccessTracking(); @@ -755,7 +764,12 @@ public class SnippetTemplate { } } } - snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements); + try (InliningLog.UpdateScope updateScope = snippetCopy.getInliningLog().openDefaultUpdateScope()) { + UnmodifiableEconomicMap duplicates = snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements); + if (updateScope != null) { + snippetCopy.getInliningLog().replaceLog(duplicates, snippetGraph.getInliningLog()); + } + } debug.dump(DebugContext.INFO_LEVEL, snippetCopy, "Before specialization"); @@ -1396,8 +1410,7 @@ public class SnippetTemplate { StructuredGraph replaceeGraph = replacee.graph(); EconomicMap replacements = bind(replaceeGraph, metaAccess, args); replacements.put(entryPointNode, AbstractBeginNode.prevBegin(replacee)); - UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); - debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + UnmodifiableEconomicMap duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements); // Re-wire the control flow graph around the replacee FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); @@ -1490,6 +1503,27 @@ public class SnippetTemplate { } } + private UnmodifiableEconomicMap inlineSnippet(Node replacee, DebugContext debug, StructuredGraph replaceeGraph, EconomicMap replacements) { + Mark mark = replaceeGraph.getMark(); + try (InliningLog.UpdateScope scope = replaceeGraph.getInliningLog().openUpdateScope((oldNode, newNode) -> { + InliningLog log = replaceeGraph.getInliningLog(); + if (oldNode == null) { + log.trackNewCallsite(newNode); + } + })) { + UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); + if (scope != null) { + replaceeGraph.getInliningLog().addLog(duplicates, snippet.getInliningLog()); + } + NodeSourcePosition position = replacee.getNodeSourcePosition(); + if (position != null) { + InliningUtil.updateSourcePosition(replaceeGraph, duplicates, mark, position, true); + } + debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + return duplicates; + } + } + private void propagateStamp(Node node) { if (node instanceof PhiNode) { PhiNode phi = (PhiNode) node; @@ -1549,8 +1583,7 @@ public class SnippetTemplate { StructuredGraph replaceeGraph = replacee.graph(); EconomicMap replacements = bind(replaceeGraph, metaAccess, args); replacements.put(entryPointNode, tool.getCurrentGuardAnchor().asNode()); - UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); - debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + UnmodifiableEconomicMap duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements); FixedWithNextNode lastFixedNode = tool.lastFixedNode(); assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph + " lastFixed=" + lastFixedNode; @@ -1611,8 +1644,7 @@ public class SnippetTemplate { floatingNodes.add(n); } } - UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(floatingNodes, snippet, floatingNodes.size(), replacements); - debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + UnmodifiableEconomicMap duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements); rewireFrameStates(replacee, duplicates); updateStamps(replacee, duplicates); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index ddc64e3839d..8793b1eba4d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -385,6 +385,23 @@ public class StandardGraphBuilderPlugins { if (allowDeoptimization) { for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long}) { Class type = kind.toJavaClass(); + + r.register1("decrementExact", type, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) { + b.addPush(kind, new IntegerSubExactNode(x, ConstantNode.forIntegerKind(kind, 1))); + return true; + } + }); + + r.register1("incrementExact", type, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) { + b.addPush(kind, new IntegerAddExactNode(x, ConstantNode.forIntegerKind(kind, 1))); + return true; + } + }); + r.register2("addExact", type, type, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { @@ -392,6 +409,7 @@ public class StandardGraphBuilderPlugins { return true; } }); + r.register2("subtractExact", type, type, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { @@ -399,6 +417,7 @@ public class StandardGraphBuilderPlugins { return true; } }); + r.register2("multiplyExact", type, type, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java index b0d8b1aa89f..eee3b1a9643 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java @@ -63,5 +63,5 @@ public class StringSubstitutions { /** * Will be intrinsified with an {@link InvocationPlugin} to a {@link LoadFieldNode}. */ - private static native char[] getValue(String s); + public static native char[] getValue(String s); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java index 88403c39fa4..f3d9ea9faed 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java @@ -101,8 +101,8 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider { private static InputStream getClassfileAsStream(Class c) { String classfilePath = c.getName().replace('.', '/') + ".class"; if (JDK9Method.JAVA_SPECIFICATION_VERSION >= 9) { - Object module = getModule.invoke(c); - return getResourceAsStream.invoke(module, classfilePath); + Object module = getModule(c); + return getResourceAsStream(module, classfilePath); } else { ClassLoader cl = c.getClassLoader(); if (cl == null) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java new file mode 100644 index 00000000000..f290b2494fb --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.replacements.nodes; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1024; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1024; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValueNodeUtil; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +import org.graalvm.compiler.nodes.memory.MemoryNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.spi.Virtualizable; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.word.LocationIdentity; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +// JaCoCo Exclude + +/** + * Compares two arrays lexicographically. + */ +@NodeInfo(cycles = CYCLES_1024, size = SIZE_1024) +public final class ArrayCompareToNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess { + + public static final NodeClass TYPE = NodeClass.create(ArrayCompareToNode.class); + + /** {@link JavaKind} of one array to compare. */ + protected final JavaKind kind1; + + /** {@link JavaKind} of the other array to compare. */ + protected final JavaKind kind2; + + /** One array to be tested for equality. */ + @Input ValueNode array1; + + /** The other array to be tested for equality. */ + @Input ValueNode array2; + + /** Length of one array. */ + @Input ValueNode length1; + + /** Length of the other array. */ + @Input ValueNode length2; + + @OptionalInput(Memory) MemoryNode lastLocationAccess; + + public ArrayCompareToNode(ValueNode array1, ValueNode array2, ValueNode length1, ValueNode length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2) { + super(TYPE, StampFactory.forKind(JavaKind.Int)); + this.kind1 = kind1; + this.kind2 = kind2; + this.array1 = array1; + this.array2 = array2; + this.length1 = length1; + this.length2 = length2; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (tool.allUsagesAvailable() && hasNoUsages()) { + return null; + } + ValueNode a1 = GraphUtil.unproxify(array1); + ValueNode a2 = GraphUtil.unproxify(array2); + if (a1 == a2) { + return ConstantNode.forInt(0); + } + return this; + } + + @Override + public void virtualize(VirtualizerTool tool) { + ValueNode alias1 = tool.getAlias(array1); + ValueNode alias2 = tool.getAlias(array2); + if (alias1 == alias2) { + // the same virtual objects will always have the same contents + tool.replaceWithValue(ConstantNode.forInt(0, graph())); + } + } + + @NodeIntrinsic + public static native int compareTo(Object array1, Object array2, int length1, int length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2); + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value result = gen.getLIRGeneratorTool().emitArrayCompareTo(kind1, kind2, gen.operand(array1), gen.operand(array2), gen.operand(length1), gen.operand(length2)); + gen.setResult(this, result); + } + + @Override + public LocationIdentity getLocationIdentity() { + return NamedLocationIdentity.getArrayLocation(kind1); + } + + @Override + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + @Override + public void setLastLocationAccess(MemoryNode lla) { + updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla)); + lastLocationAccess = lla; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java index 1c336b1517d..9372e31edfc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java @@ -29,12 +29,16 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeInputList; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.Invokable; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.InvokeNode; @@ -75,7 +79,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; size = SIZE_UNKNOWN, sizeRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate") //@formatter:on -public abstract class MacroNode extends FixedWithNextNode implements Lowerable { +public abstract class MacroNode extends FixedWithNextNode implements Lowerable, Invokable { public static final NodeClass TYPE = NodeClass.create(MacroNode.class); @Input protected NodeInputList arguments; @@ -108,10 +112,12 @@ public abstract class MacroNode extends FixedWithNextNode implements Lowerable { return arguments.toArray(new ValueNode[0]); } - public int getBci() { + @Override + public int bci() { return bci; } + @Override public ResolvedJavaMethod getTargetMethod() { return targetMethod; } @@ -120,6 +126,16 @@ public abstract class MacroNode extends FixedWithNextNode implements Lowerable { return null; } + @Override + protected void afterClone(Node other) { + updateInliningLogAfterClone(other); + } + + @Override + public FixedNode asFixedNode() { + return this; + } + /** * Gets a snippet to be used for lowering this macro node. The returned graph (if non-null) must * have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool) lowered}. @@ -196,10 +212,13 @@ public abstract class MacroNode extends FixedWithNextNode implements Lowerable { } } + @SuppressWarnings("try") public InvokeNode replaceWithInvoke() { - InvokeNode invoke = createInvoke(); - graph().replaceFixedWithFixed(this, invoke); - return invoke; + try (DebugCloseable context = withNodeSourcePosition()) { + InvokeNode invoke = createInvoke(); + graph().replaceFixedWithFixed(this, invoke); + return invoke; + } } protected InvokeNode createInvoke() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java index ee3df767dcf..08535f3f95c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java @@ -85,7 +85,7 @@ public abstract class MacroStateSplitNode extends MacroNode implements StateSpli } assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI; // Here we need to fix the bci of the invoke - InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci())); + InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), bci())); newInvoke.setStateAfter(invoke.stateAfter()); snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java index 1f0a4483b4b..7821191c735 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java @@ -54,14 +54,18 @@ public final class GraalServices { * @param other all JVMCI packages will be opened to the module defining this class */ public static void openJVMCITo(Class other) { - Object jvmci = getModule.invoke(Services.class); - Object otherModule = getModule.invoke(other); + Object jvmci = getModule(Services.class); + Object otherModule = getModule(other); if (jvmci != otherModule) { - Set packages = getPackages.invoke(jvmci); + Set packages = getPackages(jvmci); for (String pkg : packages) { - boolean opened = isOpenTo.invoke(jvmci, pkg, otherModule); + boolean opened = isOpenTo(jvmci, pkg, otherModule); if (!opened) { - addOpens.invoke(jvmci, pkg, otherModule); + try { + addOpens.invoke(jvmci, pkg, otherModule); + } catch (Throwable throwable) { + throw new InternalError(throwable); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java index 17c8ae0dbbb..e8eb639db2b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java @@ -22,9 +22,11 @@ */ package org.graalvm.compiler.serviceprovider; -import java.lang.reflect.InvocationTargetException; +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.util.Set; /** * Reflection based access to API introduced by JDK 9. This allows the API to be used in code that @@ -46,9 +48,17 @@ public final class JDK9Method { */ public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion(); - public JDK9Method(Class declaringClass, String name, Class... parameterTypes) { + public static MethodHandle lookupMethodHandle(Class declaringClass, String name, Class... parameterTypes) { try { - this.method = declaringClass.getMethod(name, parameterTypes); + return MethodHandles.lookup().unreflect(declaringClass.getMethod(name, parameterTypes)); + } catch (Exception e) { + throw new InternalError(e); + } + } + + private static Method lookupMethod(Class declaringClass, String name, Class... parameterTypes) { + try { + return declaringClass.getMethod(name, parameterTypes); } catch (Exception e) { throw new InternalError(e); } @@ -59,90 +69,85 @@ public final class JDK9Method { */ public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8; - public final Method method; - - public Class getReturnType() { - return method.getReturnType(); - } - /** * {@code Class.getModule()}. */ - public static final JDK9Method getModule; + private static final MethodHandle getModuleHandle; + + public static Object getModule(Class clazz) { + try { + return getModuleHandle.invoke(clazz); + } catch (Throwable throwable) { + throw new InternalError(throwable); + } + } /** * {@code java.lang.Module.getPackages()}. */ - public static final JDK9Method getPackages; + private static final MethodHandle getPackages; + + public static Set getPackages(Object module) { + try { + return (Set) getPackages.invoke(module); + } catch (Throwable throwable) { + throw new InternalError(throwable); + } + } /** * {@code java.lang.Module.getResourceAsStream(String)}. */ - public static final JDK9Method getResourceAsStream; + private static final MethodHandle getResourceAsStream; + + public static InputStream getResourceAsStream(Object module, String resource) { + try { + return (InputStream) getResourceAsStream.invoke(module, resource); + } catch (Throwable throwable) { + throw new InternalError(throwable); + } + } /** - * {@code java.lang.Module.addOpens(String, Module)}. + * {@code java.lang.Module.addOpens(String, Module)}. This only seems to work correctly when + * invoked through reflection. */ - public static final JDK9Method addOpens; + public static final Method addOpens; /** * {@code java.lang.Module.isOpen(String, Module)}. */ - public static final JDK9Method isOpenTo; + private static final MethodHandle isOpenTo; - /** - * Invokes the static Module API method represented by this object. - */ - @SuppressWarnings("unchecked") - public T invokeStatic(Object... args) { - checkAvailability(); - assert Modifier.isStatic(method.getModifiers()); + public static boolean isOpenTo(Object module1, String pkg, Object module2) { try { - return (T) method.invoke(null, args); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new InternalError(e); + return (boolean) isOpenTo.invoke(module1, pkg, module2); + } catch (Throwable throwable) { + throw new InternalError(throwable); } } - /** - * Invokes the non-static Module API method represented by this object. - */ - @SuppressWarnings("unchecked") - public T invoke(Object receiver, Object... args) { - checkAvailability(); - assert !Modifier.isStatic(method.getModifiers()); - try { - return (T) method.invoke(receiver, args); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new InternalError(e); - } - } - - private void checkAvailability() throws InternalError { - if (method == null) { - throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION); - } - } + public static final Class MODULE_CLASS; static { if (JAVA_SPECIFICATION_VERSION >= 9) { - getModule = new JDK9Method(Class.class, "getModule"); - Class moduleClass = getModule.getReturnType(); - getPackages = new JDK9Method(moduleClass, "getPackages"); - addOpens = new JDK9Method(moduleClass, "addOpens", String.class, moduleClass); - getResourceAsStream = new JDK9Method(moduleClass, "getResourceAsStream", String.class); - isOpenTo = new JDK9Method(moduleClass, "isOpen", String.class, moduleClass); + try { + MODULE_CLASS = Class.class.getMethod("getModule").getReturnType(); + getModuleHandle = lookupMethodHandle(Class.class, "getModule"); + getPackages = lookupMethodHandle(MODULE_CLASS, "getPackages"); + addOpens = lookupMethod(MODULE_CLASS, "addOpens", String.class, MODULE_CLASS); + getResourceAsStream = lookupMethodHandle(MODULE_CLASS, "getResourceAsStream", String.class); + isOpenTo = lookupMethodHandle(MODULE_CLASS, "isOpen", String.class, MODULE_CLASS); + } catch (NoSuchMethodException e) { + throw new InternalError(e); + } } else { - JDK9Method unavailable = new JDK9Method(); - getModule = unavailable; - getPackages = unavailable; - addOpens = unavailable; - getResourceAsStream = unavailable; - isOpenTo = unavailable; + MODULE_CLASS = null; + getModuleHandle = null; + getPackages = null; + addOpens = null; + getResourceAsStream = null; + isOpenTo = null; } } - - private JDK9Method() { - method = null; - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java index a6ef36838e1..2bb39b3c0cd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java @@ -128,7 +128,11 @@ final class ProtocolImpl) && findJavaTypeName(type) == null) { + throw new IllegalStateException("nodeClassType method shall return a Java class (instance of Class)! Was: " + type); + } + return type; } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java index b6c8a127314..a5a7925e724 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java @@ -45,6 +45,7 @@ public class StringBenchmark extends BenchmarkBase { // Checkstyle: stop String lorem = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + String loremLastChar = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum?"; // Checkstyle: resume } @@ -71,4 +72,10 @@ public class StringBenchmark extends BenchmarkBase { public int indexOfStringNotFound(BenchState state) { return state.lorem.indexOf(state.s2); } + + @Benchmark + @Warmup(iterations = 5) + public int compareTo(BenchState state) { + return state.lorem.compareTo(state.loremLastChar); + } }