--- old/src/jdk.internal.vm.compiler/.mx.graal/suite.py 2017-08-03 22:42:37.162819746 -0700 +++ new/src/jdk.internal.vm.compiler/.mx.graal/suite.py 2017-08-03 22:42:37.063815308 -0700 @@ -179,6 +179,14 @@ "workingSets" : "Graal", }, + "org.graalvm.graphio" : { + "subDir" : "share/classes", + "sourceDirs" : ["src"], + "checkstyle" : "org.graalvm.compiler.graph", + "javaCompliance" : "1.8", + "workingSets" : "API,Graal", + }, + "org.graalvm.util" : { "subDir" : "share/classes", "sourceDirs" : ["src"], @@ -1011,6 +1019,7 @@ "subDir" : "share/classes", "sourceDirs" : ["src"], "dependencies" : [ + "org.graalvm.graphio", "org.graalvm.compiler.core", "org.graalvm.compiler.java", ], @@ -1138,6 +1147,13 @@ ], }, + "GRAAL_GRAPHIO" : { + "subDir" : "share/classes", + "dependencies" : ["org.graalvm.graphio"], + "distDependencies" : [ + ], + }, + "GRAAL_OPTIONS_PROCESSOR" : { "subDir" : "share/classes", "dependencies" : ["org.graalvm.compiler.options.processor"], @@ -1203,6 +1219,7 @@ "distDependencies" : [ "GRAAL_API", "GRAAL_COMPILER", + "GRAAL_GRAPHIO", ], }, @@ -1297,6 +1314,7 @@ "GRAAL" : { "subDir" : "share/classes", "overlaps" : [ + "GRAAL_GRAPHIO", "GRAAL_OPTIONS", "GRAAL_NODEINFO", "GRAAL_API", --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java 2017-08-03 22:42:37.502834988 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java 2017-08-03 22:42:37.406830685 -0700 @@ -94,7 +94,7 @@ } } - protected Value emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state) { + public Value emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state) { // Issue a zero extending load of the proper bit size and set the result to // the proper kind. Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AArch64Kind.DWORD : AArch64Kind.QWORD)); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java 2017-08-03 22:42:37.838850051 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java 2017-08-03 22:42:37.736845478 -0700 @@ -24,14 +24,9 @@ package org.graalvm.compiler.core.aarch64; import org.graalvm.compiler.core.gen.NodeMatchRules; -import org.graalvm.compiler.core.match.ComplexMatchResult; -import org.graalvm.compiler.core.match.MatchRule; import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; import org.graalvm.compiler.nodes.DeoptimizingNode; -import org.graalvm.compiler.nodes.calc.SignExtendNode; -import org.graalvm.compiler.nodes.calc.ZeroExtendNode; import org.graalvm.compiler.nodes.memory.Access; import jdk.vm.ci.aarch64.AArch64Kind; @@ -61,18 +56,4 @@ protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() { return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); } - - @MatchRule("(ZeroExtend Read=access)") - @MatchRule("(ZeroExtend FloatingRead=access)") - public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) { - AArch64Kind memoryKind = getMemoryKind(access); - return builder -> getArithmeticLIRGenerator().emitExtendMemory(false, memoryKind, root.getResultBits(), (AArch64AddressValue) operand(access.getAddress()), getState(access)); - } - - @MatchRule("(SignExtend Read=access)") - @MatchRule("(SignExtend FloatingRead=access)") - public ComplexMatchResult signExtend(SignExtendNode root, Access access) { - AArch64Kind memoryKind = getMemoryKind(access); - return builder -> getArithmeticLIRGenerator().emitExtendMemory(true, memoryKind, root.getResultBits(), (AArch64AddressValue) operand(access.getAddress()), getState(access)); - } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java 2017-08-03 22:42:38.176865203 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java 2017-08-03 22:42:38.077860765 -0700 @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.core.common; -import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; @@ -269,9 +268,6 @@ @Option(help = "Use a cache for snippet graphs.", type = OptionType.Debug) public static final OptionKey UseSnippetGraphCache = new OptionKey<>(true); - @Option(help = "Enable expensive assertions.", type = OptionType.Debug) - public static final OptionKey DetailedAsserts = new OptionKey<>(Assertions.ENABLED); - @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug) public static final OptionKey TraceRA = new OptionKey<>(false); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java 2017-08-03 22:42:38.511880221 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java 2017-08-03 22:42:38.414875873 -0700 @@ -111,6 +111,7 @@ import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.phases.tiers.TargetProvider; import org.graalvm.compiler.phases.util.Providers; @@ -595,6 +596,10 @@ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); } + protected MidTierContext getDefaultMidTierContext() { + return new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, null); + } + protected SnippetReflectionProvider getSnippetReflection() { return Graal.getRequiredCapability(SnippetReflectionProvider.class); } @@ -926,7 +931,7 @@ */ @SuppressWarnings("try") protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) { - if (!forceCompile) { + if (!forceCompile && graph == null) { InstalledCode cached = cache.get(installedCodeOwner); if (cached != null) { if (cached.isValid()) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java 2017-08-03 22:42:38.856895687 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java 2017-08-03 22:42:38.756891204 -0700 @@ -38,6 +38,10 @@ private static final long fieldOffset1; private static final long fieldOffset2; + private static final long byteArrayBaseOffset; + private static final long intArrayBaseOffset; + private static final long longArrayBaseOffset; + static { try { long localFieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("x")); @@ -51,6 +55,9 @@ fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("z")); } assert fieldOffset2 == fieldOffset1 + 4; + byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class); + intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class); + longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class); } catch (Exception e) { throw new RuntimeException(e); } @@ -195,4 +202,77 @@ } return x; } + + public static int testWriteIntToByteArraySnippet() { + byte[] array = new byte[4]; + UNSAFE.putInt(array, byteArrayBaseOffset, 0x01020304); + return array[0]; + } + + @Test + public void testWriteIntToByteArray() { + test("testWriteIntToByteArraySnippet"); + } + + public static byte testWriteSignedExtendedByteToByteArraySnippet(byte b) { + byte[] array = new byte[4]; + array[0] = 0x01; + array[1] = 0x02; + array[2] = 0x03; + array[3] = 0x04; + UNSAFE.putInt(array, byteArrayBaseOffset, b); + return array[3]; + } + + @Test + public void testWriteSignedExtendedByteToByteArray() { + test("testWriteSignedExtendedByteToByteArraySnippet", (byte) 0); + } + + public static int testWriteLongToIntArraySnippet() { + int[] array = new int[2]; + UNSAFE.putLong(array, intArrayBaseOffset, 0x0102030405060708L); + return array[0]; + } + + @Test + public void testWriteLongToIntArray() { + test("testWriteLongToIntArraySnippet"); + } + + public static int testWriteByteToIntArraySnippet() { + int[] array = new int[1]; + array[0] = 0x01020304; + UNSAFE.putByte(array, intArrayBaseOffset, (byte) 0x05); + return array[0]; + } + + @Test + public void testWriteByteToIntArray() { + test("testWriteByteToIntArraySnippet"); + } + + public static long testWriteIntToLongArraySnippet() { + long[] array = new long[1]; + array[0] = 0x0102030405060708L; + UNSAFE.putInt(array, longArrayBaseOffset, 0x04030201); + return array[0]; + } + + @Test + public void testWriteIntToLongArray() { + test("testWriteIntToLongArraySnippet"); + } + + public static float testWriteFloatToIntArraySnippet() { + float[] array = new float[1]; + UNSAFE.putInt(array, intArrayBaseOffset, Float.floatToRawIntBits(0.5f)); + return array[0]; + } + + @Test + public void testWriteFloatToIntArray() { + test("testWriteFloatToIntArraySnippet"); + } + } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java 2017-08-03 22:42:39.191910705 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java 2017-08-03 22:42:39.093906312 -0700 @@ -227,7 +227,7 @@ */ @Test public void testInvariantChecking() throws InterruptedException { - Assume.assumeTrue(Assertions.ENABLED); + Assume.assumeTrue(Assertions.assertionsEnabled()); EconomicMap, Object> map = EconomicMap.create(); // Configure with an option that enables counters map.put(DebugOptions.Counters, ""); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Assertions.java 2017-08-03 22:42:39.524925633 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Assertions.java 2017-08-03 22:42:39.428921330 -0700 @@ -22,6 +22,11 @@ */ package org.graalvm.compiler.debug; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValues; + /** * Utility for query whether assertions are enabled. */ @@ -30,11 +35,28 @@ * Determines if assertions are enabled. Strictly speaking, this may only be true for the * {@link Assertions} class but we assume assertions are enabled/disabled for Graal as a whole. */ - public static final boolean ENABLED = assertionsEnabled(); - - private static boolean assertionsEnabled() { + public static boolean assertionsEnabled() { boolean enabled = false; assert (enabled = true) == true; return enabled; } + + /** + * Determines if detailed assertions are enabled. This requires that the normal assertions are + * also enabled. + * + * @param values the current OptionValues that might define a value for DetailAsserts. + */ + public static boolean detailedAssertionsEnabled(OptionValues values) { + return assertionsEnabled() && Options.DetailedAsserts.getValue(values); + } + + // @formatter:off + public static class Options { + + @Option(help = "Enable expensive assertions. (Require normal assertions enabled)", type = OptionType.Debug) + public static final OptionKey DetailedAsserts = new OptionKey<>(true); + + } + // @formatter:on } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java 2017-08-03 22:42:39.857940561 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java 2017-08-03 22:42:39.757936078 -0700 @@ -65,7 +65,7 @@ DebugOptions.TrackMemUse.getValue(options), DebugOptions.Time.getValue(options), DebugOptions.Dump.getValue(options), - DebugOptions.Verify.getValue(options), + getVerifyOptionValue(options), DebugOptions.MethodFilter.getValue(options), output, dumpHandlers, verifyHandlers); } @@ -99,6 +99,10 @@ this.output = output; } + private static String getVerifyOptionValue(OptionValues values) { + return !DebugOptions.Verify.hasBeenSet(values) && Assertions.assertionsEnabled() ? "" : DebugOptions.Verify.getValue(values); + } + @Override public OptionValues getOptions() { return options; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java 2017-08-03 22:42:40.190955490 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java 2017-08-03 22:42:40.091951051 -0700 @@ -32,11 +32,9 @@ import static org.graalvm.compiler.debug.DebugOptions.ListMetrics; import static org.graalvm.compiler.debug.DebugOptions.Log; import static org.graalvm.compiler.debug.DebugOptions.MemUseTrackers; -import static org.graalvm.compiler.debug.DebugOptions.MethodFilter; import static org.graalvm.compiler.debug.DebugOptions.Time; import static org.graalvm.compiler.debug.DebugOptions.Timers; import static org.graalvm.compiler.debug.DebugOptions.TrackMemUse; -import static org.graalvm.compiler.debug.DebugOptions.Verify; import java.io.ByteArrayOutputStream; import java.io.File; @@ -374,16 +372,7 @@ } } } - currentConfig = new DebugConfigImpl( - options, - Log.getValue(options), - Count.getValue(options), - TrackMemUse.getValue(options), - Time.getValue(options), - Dump.getValue(options), - Verify.getValue(options), - MethodFilter.getValue(options), - logStream, dumpHandlers, verifyHandlers); + currentConfig = new DebugConfigImpl(options, logStream, dumpHandlers, verifyHandlers); currentScope = new ScopeImpl(this, Thread.currentThread()); currentScope.updateFlags(currentConfig); metricsEnabled = true; @@ -575,7 +564,7 @@ } } - private final Invariants invariants = Assertions.ENABLED ? new Invariants() : null; + private final Invariants invariants = Assertions.assertionsEnabled() ? new Invariants() : null; static StackTraceElement[] getStackTrace(Thread thread) { return thread.getStackTrace(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java 2017-08-03 22:42:40.538971090 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java 2017-08-03 22:42:40.441966742 -0700 @@ -75,7 +75,7 @@ public static final OptionKey Time = new OptionKey<>(null); @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify).", type = OptionType.Debug) - public static final OptionKey Verify = new OptionKey<>(Assertions.ENABLED ? "" : null); + public static final OptionKey Verify = new OptionKey<>(null); @Option(help = "Pattern for scope(s) in which dumping is enabled (see DebugFilter and Debug.dump)", type = OptionType.Debug) public static final OptionKey Dump = new OptionKey<>(null); @Option(help = "Pattern for scope(s) in which logging is enabled (see DebugFilter and Debug.log)", type = OptionType.Debug) @@ -115,7 +115,7 @@ @Option(help = "The directory where various Graal dump files are written.") public static final OptionKey DumpPath = new OptionKey<>("dumps"); @Option(help = "Print the name of each dump file path as it's created.") - public static final OptionKey ShowDumpFiles = new OptionKey<>(Assertions.ENABLED); + public static final OptionKey ShowDumpFiles = new OptionKey<>(false); @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.", type = OptionType.Debug) public static final OptionKey PrintCFG = new OptionKey<>(false); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java 2017-08-03 22:42:40.878986333 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java 2017-08-03 22:42:40.780981939 -0700 @@ -148,7 +148,8 @@ @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (attrs.isRegularFile()) { - ZipEntry ze = new ZipEntry(file.toString()); + String name = dir.relativize(file).toString(); + ZipEntry ze = new ZipEntry(name); zos.putNextEntry(ze); zos.write(Files.readAllBytes(file)); zos.closeEntry(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java 2017-08-03 22:42:41.216001440 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java 2017-08-03 22:42:41.119997137 -0700 @@ -119,7 +119,7 @@ TestNode newNode = graph.add(new TestNode()); try { map.get(newNode); - fail("expected " + (Assertions.ENABLED ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); + fail("expected " + (Assertions.assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); } catch (AssertionError ae) { // thrown when assertions are enabled } catch (ArrayIndexOutOfBoundsException e) { @@ -136,7 +136,7 @@ TestNode newNode = graph.add(new TestNode()); try { map.set(newNode, 1); - fail("expected " + (Assertions.ENABLED ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); + fail("expected " + (Assertions.assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); } catch (AssertionError ae) { // thrown when assertions are enabled } catch (ArrayIndexOutOfBoundsException e) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java 2017-08-03 22:42:41.552016503 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java 2017-08-03 22:42:41.455012154 -0700 @@ -31,9 +31,11 @@ import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase; import org.graalvm.compiler.phases.common.ExpandLogicPhase; import org.graalvm.compiler.phases.common.FixReadsPhase; +import org.graalvm.compiler.phases.common.PropagateDeoptimizeProbabilityPhase; import org.graalvm.compiler.phases.tiers.LowTierContext; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.phases.tiers.SuitesCreator; +import org.graalvm.compiler.replacements.aarch64.AArch64ReadReplacementPhase; import java.util.ListIterator; @@ -60,6 +62,9 @@ } findPhase.add(new AddressLoweringByUsePhase(addressLoweringByUse)); + findPhase = suites.getLowTier().findPhase(PropagateDeoptimizeProbabilityPhase.class); + findPhase.add(new AArch64ReadReplacementPhase()); + return suites; } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesCreator.java 2017-08-03 22:42:41.890031656 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesCreator.java 2017-08-03 22:42:41.791027217 -0700 @@ -23,7 +23,7 @@ package org.graalvm.compiler.hotspot.amd64; import org.graalvm.compiler.core.amd64.AMD64SuitesCreator; -import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.hotspot.lir.HotSpotZapRegistersPhase; import org.graalvm.compiler.lir.phases.LIRSuites; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; @@ -39,7 +39,7 @@ @Override public LIRSuites createLIRSuites(OptionValues options) { LIRSuites lirSuites = super.createLIRSuites(options); - if (GraalOptions.DetailedAsserts.getValue(options)) { + if (Assertions.detailedAssertionsEnabled(options)) { lirSuites.getPostAllocationOptimizationStage().appendPhase(new HotSpotZapRegistersPhase()); } return lirSuites; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java 2017-08-03 22:42:42.228046808 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java 2017-08-03 22:42:42.131042460 -0700 @@ -82,6 +82,8 @@ "test"); } + private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose"); + private static void testHelper(List extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException { final File dumpPath = new File(CompilationWrapperTest.class.getSimpleName() + "_" + System.currentTimeMillis()).getAbsoluteFile(); List vmArgs = withoutDebuggerArguments(getVMCommandLine()); @@ -92,7 +94,9 @@ vmArgs.addAll(extraVmArgs); Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs); - System.out.println(proc); + if (VERBOSE) { + System.out.println(proc); + } String forcedCrashString = "Forced crash after compiling"; String diagnosticOutputFilePrefix = "Graal diagnostic output saved in "; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java 2017-08-03 22:42:42.565061916 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java 2017-08-03 22:42:42.468057567 -0700 @@ -53,6 +53,7 @@ import jdk.vm.ci.hotspot.HotSpotCompilationRequest; import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult; import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; import jdk.vm.ci.hotspot.HotSpotNmethod; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -145,7 +146,7 @@ * respect CompilationFailureAction if it has been explicitly set. */ if (actionKey == CompilationFailureAction && !actionKey.hasBeenSet(values)) { - if (Assertions.ENABLED || compiler.getGraalRuntime().isBootstrapping()) { + if (Assertions.assertionsEnabled() || compiler.getGraalRuntime().isBootstrapping()) { return ExitVM; } } @@ -305,6 +306,10 @@ if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { return HotSpotCompilationRequestResult.failure("Already compiled", false); } + if (HotSpotGraalCompilerFactory.checkGraalCompileOnlyFilter(method.getDeclaringClass().toJavaName(), method.getName(), method.getSignature().toString(), + HotSpotJVMCICompilerFactory.CompilationLevel.FullOptimization) != HotSpotJVMCICompilerFactory.CompilationLevel.FullOptimization) { + return HotSpotCompilationRequestResult.failure("GraalCompileOnly excluded", false); + } } HotSpotCompilationWrapper compilation = new HotSpotCompilationWrapper(compilationEvent); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java 2017-08-03 22:42:42.903077068 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java 2017-08-03 22:42:42.806072720 -0700 @@ -130,7 +130,7 @@ * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all * {@link CompilerConfigurationFactory} instances. */ - private static final List factories = Assertions.ENABLED ? new ArrayList<>() : null; + private static final List factories = Assertions.assertionsEnabled() ? new ArrayList<>() : null; private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) { for (CompilerConfigurationFactory other : factories) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java 2017-08-03 22:42:43.233091862 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java 2017-08-03 22:42:43.136087514 -0700 @@ -162,9 +162,20 @@ * This method is static so it can be exercised during initialization. */ private static 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; + } + } + } + return checkGraalCompileOnlyFilter(declaringClass.getName(), name, signature, level); + } + + public static CompilationLevel checkGraalCompileOnlyFilter(String declaringClassName, String name, String signature, CompilationLevel level) { if (graalCompileOnlyFilter != null) { if (level == CompilationLevel.FullOptimization) { - String declaringClassName = declaringClass.getName(); HotSpotSignature sig = null; for (MethodFilter filter : graalCompileOnlyFilter) { if (filter.hasSignature() && sig == null) { @@ -177,14 +188,6 @@ return CompilationLevel.Simple; } } - 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; - } - } - } return level; } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java 2017-08-03 22:42:43.564106701 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java 2017-08-03 22:42:43.468102398 -0700 @@ -138,8 +138,6 @@ if (build >= JVMCI9_MIN_EA_BUILD) { return; } - // Using Object.equals suppresses Eclipse's "Dead code" warning. - // Unfortunately @SuppressWarnings("unused") can only be applied at method level. if (Objects.equals(JVMCI9_MIN_EA_BUILD, Integer.MAX_VALUE)) { failVersionCheck(exitOnFailure, "This version of Graal is not compatible with any JDK 9 Early Access build.%n"); } else { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java 2017-08-03 22:42:43.902121854 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java 2017-08-03 22:42:43.804117460 -0700 @@ -153,7 +153,7 @@ @Fold @SuppressWarnings("all") static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { - return Assertions.ENABLED || cAssertionsEnabled(config); + return Assertions.assertionsEnabled() || cAssertionsEnabled(config); } public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java 2017-08-03 22:42:44.240137007 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java 2017-08-03 22:42:44.142132613 -0700 @@ -116,7 +116,7 @@ @Fold @SuppressWarnings("all") static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { - return Assertions.ENABLED || cAssertionsEnabled(config); + return Assertions.assertionsEnabled() || cAssertionsEnabled(config); } public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class, --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2017-08-03 22:42:44.578152159 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2017-08-03 22:42:44.480147766 -0700 @@ -371,6 +371,7 @@ import org.graalvm.compiler.nodes.extended.LoadHubNode; import org.graalvm.compiler.nodes.extended.LoadMethodNode; import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.extended.StateSplitProxyNode; import org.graalvm.compiler.nodes.extended.ValueAnchorNode; import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -1236,6 +1237,10 @@ } } + protected StateSplitProxyNode genVolatileFieldReadProxy(ValueNode fieldRead) { + return new StateSplitProxyNode(fieldRead); + } + protected ValueNode emitExplicitNullCheck(ValueNode receiver) { if (StampTool.isPointerNonNull(receiver.stamp())) { return receiver; @@ -1429,7 +1434,7 @@ createNonInlinedInvoke(withExceptionEdge, bci(), callTarget, resultType); } - private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) { + protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) { ResolvedJavaMethod targetMethod = initialTargetMethod; InvokeKind invokeKind = initialInvokeKind; if (initialInvokeKind.isIndirect()) { @@ -1676,7 +1681,7 @@ final Mark mark; InvocationPluginAssertions(InvocationPlugin plugin, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { - guarantee(Assertions.ENABLED, "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName()); + guarantee(Assertions.assertionsEnabled(), "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName()); this.plugin = plugin; this.targetMethod = targetMethod; this.args = args; @@ -1908,7 +1913,7 @@ } } - InvocationPluginAssertions assertions = Assertions.ENABLED ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; + 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; @@ -3788,11 +3793,22 @@ } } - frameState.push(resolvedField.getJavaKind(), append(genLoadField(receiver, resolvedField))); + ValueNode fieldRead = append(genLoadField(receiver, resolvedField)); + if (resolvedField.getDeclaringClass().getName().equals("Ljava/lang/ref/Reference;") && resolvedField.getName().equals("referent")) { LocationIdentity referentIdentity = new FieldLocationIdentity(resolvedField); append(new MembarNode(0, referentIdentity)); } + + JavaKind fieldKind = resolvedField.getJavaKind(); + + if (resolvedField.isVolatile() && fieldRead instanceof LoadFieldNode) { + StateSplitProxyNode readProxy = append(genVolatileFieldReadProxy(fieldRead)); + frameState.push(fieldKind, readProxy); + readProxy.setStateAfter(frameState.create(stream.nextBCI(), readProxy)); + } else { + frameState.push(fieldKind, fieldRead); + } } /** --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java 2017-08-03 22:42:44.967169598 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java 2017-08-03 22:42:44.866165070 -0700 @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.lir.alloc.lsra; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot; @@ -39,6 +38,7 @@ import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.util.IntList; import org.graalvm.compiler.core.common.util.Util; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.Variable; @@ -1140,7 +1140,7 @@ // split list of use positions result.usePosList = usePosList.splitAt(splitPos); - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { for (int i = 0; i < usePosList.size(); i++) { assert usePosList.usePos(i) < splitPos; } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java 2017-08-03 22:42:45.310184975 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java 2017-08-03 22:42:45.211180537 -0700 @@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.vm.ci.code.ValueUtil.isLegal; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization; @@ -40,6 +39,7 @@ import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.common.cfg.BlockMap; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.Indent; @@ -206,7 +206,7 @@ this.rangeEndMarker = new Range(Integer.MAX_VALUE, Integer.MAX_VALUE, null); this.intervalEndMarker = new Interval(Value.ILLEGAL, Interval.END_MARKER_OPERAND_NUMBER, null, rangeEndMarker); this.intervalEndMarker.next = intervalEndMarker; - this.detailedAsserts = DetailedAsserts.getValue(ir.getOptions()); + this.detailedAsserts = Assertions.detailedAssertionsEnabled(ir.getOptions()); } public LIRGenerationResult getLIRGenerationResult() { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java 2017-08-03 22:42:45.648200128 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java 2017-08-03 22:42:45.551195779 -0700 @@ -23,7 +23,6 @@ package org.graalvm.compiler.lir.alloc.lsra; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization; @@ -31,6 +30,7 @@ import java.util.ArrayList; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.LIRInsertionBuffer; @@ -99,7 +99,7 @@ */ Interval interval; interval = allocator.createUnhandledLists(mustStoreAtDefinition, null).getLeft(); - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { checkIntervals(debug, interval); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java 2017-08-03 22:42:45.988215370 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java 2017-08-03 22:42:45.890210977 -0700 @@ -26,7 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.asStackSlot; import static jdk.vm.ci.code.ValueUtil.isRegister; import static jdk.vm.ci.code.ValueUtil.isStackSlot; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.asVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static org.graalvm.compiler.lir.debug.LIRGenerationDebugContext.getSourceForOperandFromDebugContext; @@ -41,6 +40,7 @@ import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.common.util.BitMap2D; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.Indent; @@ -88,7 +88,7 @@ debug.dump(DebugContext.VERBOSE_LEVEL, lirGenRes.getLIR(), "Before register allocation"); computeLocalLiveSets(); computeGlobalLiveSets(); - buildIntervals(DetailedAsserts.getValue(allocator.getOptions())); + buildIntervals(Assertions.detailedAssertionsEnabled(allocator.getOptions())); } /** @@ -364,14 +364,14 @@ } } while (changeOccurred); - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { verifyLiveness(); } // check that the liveIn set of the first block is empty AbstractBlockBase startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock(); if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) { - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { reportFailure(numBlocks); } // bailout if this occurs in product mode. @@ -570,7 +570,7 @@ ValueMoveOp move = ValueMoveOp.asValueMoveOp(op); if (optimizeMethodArgument(move.getInput())) { StackSlot slot = asStackSlot(move.getInput()); - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { assert op.id() > 0 : "invalid id"; assert allocator.blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block"; assert isVariable(move.getResult()) : "result of move must be a variable"; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java 2017-08-03 22:42:46.332230792 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java 2017-08-03 22:42:46.233226354 -0700 @@ -26,7 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.asVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; @@ -42,6 +41,7 @@ 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.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.InstructionValueProcedure; @@ -224,7 +224,7 @@ debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId()); } - if (DetailedAsserts.getValue(getLIR().getOptions())) { + if (Assertions.detailedAssertionsEnabled(getLIR().getOptions())) { assert lir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; /* --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java 2017-08-03 22:42:46.669245900 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java 2017-08-03 22:42:46.571241507 -0700 @@ -26,7 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.vm.ci.code.ValueUtil.isRegister; import static jdk.vm.ci.code.ValueUtil.isStackSlot; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot; @@ -39,6 +38,7 @@ import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.util.Util; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.Variable; @@ -722,7 +722,7 @@ // do not add use positions for precolored intervals because they are never used if (registerPriority != RegisterPriority.None) { - if (DetailedAsserts.getValue(options)) { + if (Assertions.detailedAssertionsEnabled(options)) { for (int i = 0; i < numUsePos(); i++) { assert pos <= getUsePos(i) : "already added a use-position with lower position"; if (i > 0) { @@ -802,7 +802,7 @@ // split list of use positions splitUsePosAt(result, splitPos); - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { for (int i = 0; i < numUsePos(); i++) { assert getUsePos(i) < splitPos; } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java 2017-08-03 22:42:47.018261546 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java 2017-08-03 22:42:46.917257018 -0700 @@ -23,7 +23,6 @@ package org.graalvm.compiler.lir.alloc.trace.lsra; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.asVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; @@ -34,6 +33,7 @@ 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.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.LIRInsertionBuffer; @@ -84,7 +84,7 @@ * by Interval.spillDefinitionPos. */ TraceInterval interval = allocator.createUnhandledListBySpillPos(spilledIntervals); - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { checkIntervals(debug, interval); } if (debug.isLogEnabled()) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java 2017-08-03 22:42:47.351276475 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java 2017-08-03 22:42:47.253272081 -0700 @@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.vm.ci.code.ValueUtil.isLegal; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import java.util.ArrayList; @@ -39,6 +38,7 @@ 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.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.Indent; @@ -603,7 +603,7 @@ TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this, false); - if (DetailedAsserts.getValue(options)) { + if (Assertions.detailedAssertionsEnabled(options)) { verifyIntervals(); } } catch (Throwable e) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java 2017-08-03 22:42:47.689291627 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java 2017-08-03 22:42:47.592287279 -0700 @@ -23,7 +23,6 @@ package org.graalvm.compiler.lir.alloc.trace.lsra; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; import static org.graalvm.compiler.lir.LIRValueUtil.asVariable; import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; @@ -36,6 +35,7 @@ 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.debug.Assertions; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; @@ -97,7 +97,7 @@ debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId()); } - if (DetailedAsserts.getValue(allocator.getOptions())) { + if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) { assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; /* --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java 2017-08-03 22:42:48.029306870 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java 2017-08-03 22:42:47.930302432 -0700 @@ -171,7 +171,7 @@ assert frameContext != null; this.dataCache = dataCache; - if (dataBuilder.needDetailedPatchingInformation() || Assertions.ENABLED) { + if (dataBuilder.needDetailedPatchingInformation() || Assertions.assertionsEnabled()) { /* * Always enabled in debug mode, even when the VM does not request detailed information, * to increase test coverage. --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java 2017-08-03 22:42:48.364321888 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java 2017-08-03 22:42:48.265317450 -0700 @@ -24,7 +24,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; -import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.lir.alloc.AllocationStageVerifier; import org.graalvm.compiler.lir.alloc.lsra.LinearScanPhase; import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessAnalysisPhase; @@ -58,7 +58,7 @@ // currently we mark locations only if we do register allocation appendPhase(new LocationMarkerPhase()); - if (GraalOptions.DetailedAsserts.getValue(options)) { + if (Assertions.detailedAssertionsEnabled(options)) { appendPhase(new AllocationStageVerifier()); } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java 2017-08-03 22:42:48.702337041 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java 2017-08-03 22:42:48.604332648 -0700 @@ -45,12 +45,12 @@ protected void run(StructuredGraph graph, PhaseContext context) { if (graph.hasLoops()) { HashSetNodeEventListener listener = new HashSetNodeEventListener(); - try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { - boolean changed = true; - while (changed) { + boolean changed = true; + while (changed) { + changed = false; + try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { LoopsData dataCounted = new LoopsData(graph); dataCounted.detectedCountedLoops(); - changed = false; for (LoopEx loop : dataCounted.countedLoops()) { if (!LoopTransformations.isUnrollableLoop(loop)) { continue; @@ -60,19 +60,20 @@ // First perform the pre/post transformation and do the partial // unroll when we come around again. LoopTransformations.insertPrePostLoops(loop, graph); - changed = true; } else { - changed |= LoopTransformations.partialUnroll(loop, graph); + LoopTransformations.partialUnroll(loop, graph); } + changed = true; } } dataCounted.deleteUnusedNodes(); + + if (!listener.getNodes().isEmpty()) { + canonicalizer.applyIncremental(graph, context, listener.getNodes()); + listener.getNodes().clear(); + } } } - if (!listener.getNodes().isEmpty()) { - canonicalizer.applyIncremental(graph, context, listener.getNodes()); - listener.getNodes().clear(); - } } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java 2017-08-03 22:42:49.043352329 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java 2017-08-03 22:42:48.945347935 -0700 @@ -22,25 +22,13 @@ */ package org.graalvm.compiler.loop.phases; -import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize; -import static org.graalvm.compiler.loop.MathUtil.add; -import static org.graalvm.compiler.loop.MathUtil.sub; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import org.graalvm.compiler.core.common.RetryableBailoutException; -import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeWorkList; import org.graalvm.compiler.graph.Position; -import org.graalvm.compiler.loop.BasicInductionVariable; import org.graalvm.compiler.loop.CountedLoopInfo; -import org.graalvm.compiler.loop.DerivedInductionVariable; import org.graalvm.compiler.loop.InductionVariable; import org.graalvm.compiler.loop.InductionVariable.Direction; import org.graalvm.compiler.loop.LoopEx; @@ -59,23 +47,27 @@ import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.LoopBeginNode; -import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.SafepointNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.ValuePhiNode; -import org.graalvm.compiler.nodes.calc.AddNode; -import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; 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.SubNode; import org.graalvm.compiler.nodes.extended.SwitchNode; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize; +import static org.graalvm.compiler.loop.MathUtil.add; +import static org.graalvm.compiler.loop.MathUtil.sub; + public abstract class LoopTransformations { private LoopTransformations() { @@ -154,254 +146,13 @@ // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) } - public static boolean partialUnroll(LoopEx loop, StructuredGraph graph) { + public static void partialUnroll(LoopEx loop, StructuredGraph graph) { assert loop.loopBegin().isMainLoop(); graph.getDebug().log("LoopPartialUnroll %s", loop); - boolean changed = false; - CountedLoopInfo mainCounted = loop.counted(); - LoopBeginNode mainLoopBegin = loop.loopBegin(); - InductionVariable iv = mainCounted.getCounter(); - IfNode mainLimit = mainCounted.getLimitTest(); - LogicNode ifTest = mainLimit.condition(); - CompareNode compareNode = (CompareNode) ifTest; - ValueNode compareBound = null; - ValueNode curPhi = iv.valueNode(); - if (compareNode.getX() == curPhi) { - compareBound = compareNode.getY(); - } else if (compareNode.getY() == curPhi) { - compareBound = compareNode.getX(); - } + LoopFragmentInside newSegment = loop.inside().duplicate(); newSegment.insertWithinAfter(loop); - graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, "After duplication inside %s", mainLoopBegin); - ValueNode inductionNode = iv.valueNode(); - Node newStrideNode = null; - for (PhiNode mainPhiNode : mainLoopBegin.phis()) { - Node segmentOrigOp = null; - Node replacementOp = null; - changed = false; - // Rework each phi with a loop carried dependence - for (Node phiUsage : mainPhiNode.usages()) { - if (!loop.isOutsideLoop(phiUsage)) { - for (int i = 1; i < mainPhiNode.valueCount(); i++) { - ValueNode v = mainPhiNode.valueAt(i); - if (mainPhiNode != inductionNode) { - if (closureOnPhiInputToPhiUse(v, phiUsage, loop, graph)) { - segmentOrigOp = v; - Node node = newSegment.getDuplicatedNode(v); - replacementOp = updateUnrollSegmentValue(mainPhiNode, inductionNode, phiUsage, v, newSegment); - - // Update the induction phi with new stride node - mainPhiNode.setValueAt(i, (ValueNode) node); - // This is for induction variables not referenced in the loop body - if (inductionNode == v) { - newStrideNode = node; - } - changed = true; - break; - } - } else if (v == phiUsage) { - segmentOrigOp = phiUsage; - Node node = newSegment.getDuplicatedNode(phiUsage); - newStrideNode = node; - replacementOp = updateUnrollSegmentValue(mainPhiNode, inductionNode, phiUsage, phiUsage, newSegment); - - // Update the induction phi with new stride node - mainPhiNode.setValueAt(i, (ValueNode) node); - changed = true; - break; - } - } - } - if (changed) { - break; - } - } - - if (changed) { - // Patch the new segments induction uses of replacementOp with the old stride node - for (Node usage : mainPhiNode.usages()) { - if (usage != segmentOrigOp) { - if (!loop.isOutsideLoop(usage)) { - Node node = newSegment.getDuplicatedNode(usage); - if (node instanceof CompareNode) { - continue; - } - node.replaceFirstInput(replacementOp, segmentOrigOp); - } - } - } - } - } - if (changed && newStrideNode == null) { - throw GraalError.shouldNotReachHere("Can't find stride node"); - } - if (newStrideNode != null) { - // If merge the duplicate code into the loop and remove redundant code - placeNewSegmentAndCleanup(mainCounted, mainLoopBegin, newSegment); - int unrollFactor = mainLoopBegin.getUnrollFactor(); - // First restore the old pattern of the loop exit condition so we can update it one way - if (unrollFactor > 1) { - if (compareBound instanceof SubNode) { - SubNode newLimit = (SubNode) compareBound; - ValueNode oldcompareBound = newLimit.getX(); - compareNode.replaceFirstInput(newLimit, oldcompareBound); - newLimit.safeDelete(); - compareBound = oldcompareBound; - } else if (compareBound instanceof AddNode) { - AddNode newLimit = (AddNode) compareBound; - ValueNode oldcompareBound = newLimit.getX(); - compareNode.replaceFirstInput(newLimit, oldcompareBound); - newLimit.safeDelete(); - compareBound = oldcompareBound; - } - } - unrollFactor *= 2; - mainLoopBegin.setUnrollFactor(unrollFactor); - // Reset stride to include new segment in loop control. - long oldStride = iv.constantStride() * 2; - // Now update the induction op and the exit condition - if (iv instanceof BasicInductionVariable) { - BasicInductionVariable biv = (BasicInductionVariable) iv; - BinaryArithmeticNode newOp = (BinaryArithmeticNode) newStrideNode; - Stamp strideStamp = newOp.stamp(); - ConstantNode newStrideVal = graph.unique(ConstantNode.forIntegerStamp(strideStamp, oldStride)); - newOp.setY(newStrideVal); - biv.setOP(newOp); - // Now use the current unrollFactor to update the exit condition to power of two - if (unrollFactor > 1) { - if (iv.direction() == Direction.Up) { - int modulas = (unrollFactor - 1); - ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(strideStamp, modulas)); - ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal)); - compareNode.replaceFirstInput(compareBound, newLimit); - } else if (iv.direction() == Direction.Down) { - int modulas = (unrollFactor - 1); - ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(strideStamp, modulas)); - ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal)); - compareNode.replaceFirstInput(compareBound, newLimit); - } - } - mainLoopBegin.setLoopFrequency(mainLoopBegin.loopFrequency() / 2); - } - changed = true; - } - if (changed) { - graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "LoopPartialUnroll %s", loop); - } - return changed; - } - - private static Node updateUnrollSegmentValue(PhiNode mainPhiNode, Node inductionNode, Node phiUsage, Node patchNode, LoopFragmentInside newSegment) { - Node node = newSegment.getDuplicatedNode(phiUsage); - assert node != null : phiUsage; - Node replacementOp = null; - int inputCnt = 0; - for (Node input : phiUsage.inputs()) { - inputCnt++; - if (input == mainPhiNode) { - break; - } - } - int newInputCnt = 0; - for (Node input : node.inputs()) { - newInputCnt++; - if (newInputCnt == inputCnt) { - replacementOp = input; - if (mainPhiNode == inductionNode) { - node.replaceFirstInput(input, mainPhiNode); - } else { - node.replaceFirstInput(input, patchNode); - } - break; - } - } - return replacementOp; - } - - private static boolean closureOnPhiInputToPhiUse(Node inNode, Node usage, LoopEx loop, StructuredGraph graph) { - NodeWorkList nodes = graph.createNodeWorkList(); - nodes.add(inNode); - // Now walk from the inNode to usage if we can find it else we do not have closure - for (Node node : nodes) { - if (node == usage) { - return true; - } - for (Node input : node.inputs()) { - if (!loop.isOutsideLoop(input)) { - if (input != usage) { - nodes.add(input); - } else { - return true; - // For any reason if we have completed a closure, stop processing more - } - } - } - } - return false; - } - - private static void placeNewSegmentAndCleanup(CountedLoopInfo mainCounted, LoopBeginNode mainLoopBegin, LoopFragmentInside newSegment) { - // Discard the segment entry and its flow, after if merging it into the loop - StructuredGraph graph = mainLoopBegin.graph(); - IfNode loopTest = mainCounted.getLimitTest(); - IfNode newSegmentTest = newSegment.getDuplicatedNode(loopTest); - AbstractBeginNode trueSuccessor = loopTest.trueSuccessor(); - AbstractBeginNode falseSuccessor = loopTest.falseSuccessor(); - FixedNode firstNode; - boolean codeInTrueSide = false; - if (trueSuccessor == mainCounted.getBody()) { - firstNode = trueSuccessor.next(); - codeInTrueSide = true; - } else { - assert (falseSuccessor == mainCounted.getBody()); - firstNode = falseSuccessor.next(); - } - trueSuccessor = newSegmentTest.trueSuccessor(); - falseSuccessor = newSegmentTest.falseSuccessor(); - for (Node usage : falseSuccessor.anchored().snapshot()) { - usage.replaceFirstInput(falseSuccessor, loopTest.falseSuccessor()); - } - for (Node usage : trueSuccessor.anchored().snapshot()) { - usage.replaceFirstInput(trueSuccessor, loopTest.trueSuccessor()); - } - AbstractBeginNode startBlockNode; - if (codeInTrueSide) { - startBlockNode = trueSuccessor; - } else { - graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, mainLoopBegin.graph(), "before"); - startBlockNode = falseSuccessor; - } - FixedNode lastNode = getBlockEnd(startBlockNode); - LoopEndNode loopEndNode = getSingleLoopEndFromLoop(mainLoopBegin); - FixedNode lastCodeNode = (FixedNode) loopEndNode.predecessor(); - FixedNode newSegmentFirstNode = newSegment.getDuplicatedNode(firstNode); - FixedNode newSegmentLastNode = newSegment.getDuplicatedNode(lastCodeNode); - graph.getDebug().dump(DebugContext.DETAILED_LEVEL, loopEndNode.graph(), "Before placing segment"); - if (firstNode instanceof LoopEndNode) { - GraphUtil.killCFG(newSegment.getDuplicatedNode(mainLoopBegin)); - } else { - newSegmentLastNode.clearSuccessors(); - startBlockNode.setNext(lastNode); - lastCodeNode.replaceFirstSuccessor(loopEndNode, newSegmentFirstNode); - newSegmentLastNode.replaceFirstSuccessor(lastNode, loopEndNode); - FixedWithNextNode oldLastNode = (FixedWithNextNode) lastCodeNode; - oldLastNode.setNext(newSegmentFirstNode); - FixedWithNextNode newLastNode = (FixedWithNextNode) newSegmentLastNode; - newLastNode.setNext(loopEndNode); - startBlockNode.clearSuccessors(); - lastNode.safeDelete(); - Node newSegmentTestStart = newSegmentTest.predecessor(); - LogicNode newSegmentIfTest = newSegmentTest.condition(); - newSegmentTestStart.clearSuccessors(); - newSegmentTest.safeDelete(); - newSegmentIfTest.safeDelete(); - trueSuccessor.safeDelete(); - falseSuccessor.safeDelete(); - newSegmentTestStart.safeDelete(); - } - graph.getDebug().dump(DebugContext.DETAILED_LEVEL, loopEndNode.graph(), "After placing segment"); } // This function splits candidate loops into pre, main and post loops, @@ -475,12 +226,12 @@ public static void insertPrePostLoops(LoopEx loop, StructuredGraph graph) { graph.getDebug().log("LoopTransformations.insertPrePostLoops %s", loop); LoopFragmentWhole preLoop = loop.whole(); - CountedLoopInfo preCounted = preLoop.loop().counted(); + CountedLoopInfo preCounted = loop.counted(); IfNode preLimit = preCounted.getLimitTest(); if (preLimit != null) { LoopBeginNode preLoopBegin = loop.loopBegin(); InductionVariable preIv = preCounted.getCounter(); - LoopExitNode preLoopExitNode = getSingleExitFromLoop(preLoopBegin); + LoopExitNode preLoopExitNode = preLoopBegin.getSingleLoopExit(); FixedNode continuationNode = preLoopExitNode.next(); // Each duplication is inserted after the original, ergo create the post loop first @@ -497,7 +248,7 @@ EndNode postEndNode = getBlockEndAfterLoopExit(postLoopBegin); AbstractMergeNode postMergeNode = postEndNode.merge(); - LoopExitNode postLoopExitNode = getSingleExitFromLoop(postLoopBegin); + LoopExitNode postLoopExitNode = postLoopBegin.getSingleLoopExit(); // Update the main loop phi initialization to carry from the pre loop for (PhiNode prePhiNode : preLoopBegin.phis()) { @@ -511,7 +262,7 @@ // In the case of no Bounds tests, we just flow right into the main loop AbstractBeginNode mainLandingNode = BeginNode.begin(postEntryNode); - LoopExitNode mainLoopExitNode = getSingleExitFromLoop(mainLoopBegin); + LoopExitNode mainLoopExitNode = mainLoopBegin.getSingleLoopExit(); mainLoopExitNode.setNext(mainLandingNode); preLoopExitNode.setNext(mainLoopBegin.forwardEnd()); @@ -528,6 +279,14 @@ preLoopBegin.setLoopFrequency(1); mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2)); postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1)); + + // The pre and post loops don't require safepoints at all + for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) { + GraphUtil.removeFixedWithUnusedInputs(safepoint); + } + for (SafepointNode safepoint : postLoop.nodes().filter(SafepointNode.class)) { + GraphUtil.removeFixedWithUnusedInputs(safepoint); + } } graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "InsertPrePostLoops %s", loop); } @@ -573,21 +332,11 @@ } } - private static LoopExitNode getSingleExitFromLoop(LoopBeginNode curLoopBegin) { - assert curLoopBegin.loopExits().count() == 1; - return curLoopBegin.loopExits().first(); - } - - private static LoopEndNode getSingleLoopEndFromLoop(LoopBeginNode curLoopBegin) { - assert curLoopBegin.loopEnds().count() == 1; - return curLoopBegin.loopEnds().first(); - } - /** * Find the end of the block following the LoopExit. */ private static EndNode getBlockEndAfterLoopExit(LoopBeginNode curLoopBegin) { - FixedNode node = getSingleExitFromLoop(curLoopBegin).next(); + FixedNode node = curLoopBegin.getSingleLoopExit().next(); // Find the last node after the exit blocks starts return getBlockEnd(node); } @@ -693,43 +442,18 @@ } public static boolean isUnrollableLoop(LoopEx loop) { - if (!loop.isCounted()) { + if (!loop.isCounted() || !loop.counted().getCounter().isConstantStride()) { return false; } LoopBeginNode loopBegin = loop.loopBegin(); - boolean isCanonical = false; if (loopBegin.isMainLoop() || loopBegin.isSimpleLoop()) { // Flow-less loops to partial unroll for now. 3 blocks corresponds to an if that either // exits or continues the loop. There might be fixed and floating work within the loop // as well. if (loop.loop().getBlocks().size() < 3) { - isCanonical = true; - } - } - if (!isCanonical) { - return false; - } - for (ValuePhiNode phi : loopBegin.valuePhis()) { - if (phi.usages().filter(x -> loopBegin.isPhiAtMerge(x)).isNotEmpty()) { - // Filter out Phis which reference Phis at the same merge until the duplication - // logic handles it properly. - return false; - } - InductionVariable iv = loop.getInductionVariables().get(phi); - if (iv == null) { - continue; - } - if (iv instanceof DerivedInductionVariable) { - return false; - } else if (iv instanceof BasicInductionVariable) { - BasicInductionVariable biv = (BasicInductionVariable) iv; - if (!biv.isConstantStride()) { - return false; - } - } else { - return false; + return true; } } - return true; + return false; } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java 2017-08-03 22:42:49.386367706 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java 2017-08-03 22:42:49.289363357 -0700 @@ -26,24 +26,34 @@ import org.graalvm.compiler.loop.LoopEx; import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; import org.graalvm.compiler.phases.Phase; +/** + * Rearrange {@link BinaryArithmeticNode#isAssociative() associative binary operations} so that + * invariant parts of the expression can move outside of the loop. + */ public class ReassociateInvariantPhase extends Phase { @SuppressWarnings("try") @Override protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - final LoopsData dataReassociate = new LoopsData(graph); - DebugContext debug = graph.getDebug(); - try (DebugContext.Scope s = debug.scope("ReassociateInvariants")) { + int iterations = 0; + DebugContext debug = graph.getDebug(); + try (DebugContext.Scope s = debug.scope("ReassociateInvariants")) { + boolean changed = true; + while (changed) { + changed = false; + final LoopsData dataReassociate = new LoopsData(graph); for (LoopEx loop : dataReassociate.loops()) { - loop.reassociateInvariants(); + changed |= loop.reassociateInvariants(); } - } catch (Throwable e) { - throw debug.handle(e); + dataReassociate.deleteUnusedNodes(); + iterations++; + debug.dump(DebugContext.VERBOSE_LEVEL, graph, "after iteration %d", iterations); } - dataReassociate.deleteUnusedNodes(); + } catch (Throwable e) { + throw debug.handle(e); } } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java 2017-08-03 22:42:49.724382859 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java 2017-08-03 22:42:49.626378465 -0700 @@ -26,13 +26,12 @@ import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; -import org.junit.Ignore; import org.junit.Test; public class LoopPartialUnrollTest extends GraalCompilerTest { @Override - protected boolean checkLowTierGraph(StructuredGraph graph) { + protected boolean checkMidTierGraph(StructuredGraph graph) { NodeIterable loops = graph.getNodes().filter(LoopBeginNode.class); for (LoopBeginNode loop : loops) { if (loop.isMainLoop()) { @@ -45,7 +44,7 @@ public static long testMultiplySnippet(int arg) { long r = 1; for (int i = 0; branchProbability(0.99, i < arg); i++) { - r *= i; + r += r * i; } return r; } @@ -59,7 +58,24 @@ int c = 0; for (int i = 0; i < d; i++) { for (int j = 0; branchProbability(0.99, j < i); j++) { - c += j & 0x3; + c += c + j & 0x3; + } + } + return c; + } + + @Test + public void testNestedSumBy2() { + for (int i = 0; i < 1000; i++) { + test("testNestedSumBy2Snippet", i); + } + } + + public static int testNestedSumBy2Snippet(int d) { + int c = 0; + for (int i = 0; i < d; i++) { + for (int j = 0; branchProbability(0.99, j < i); j += 2) { + c += c + j & 0x3; } } return c; @@ -75,7 +91,7 @@ public static int testSumDownSnippet(int d) { int c = 0; for (int j = d; branchProbability(0.99, j > -4); j--) { - c += j & 0x3; + c += c + j & 0x3; } return c; } @@ -83,21 +99,38 @@ @Test public void testSumDown() { test("testSumDownSnippet", 1); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 160; i++) { test("testSumDownSnippet", i); } } - @Ignore("Phis which reference the backedge value of other Phis aren't handled properly") + public static int testSumDownBy2Snippet(int d) { + int c = 0; + for (int j = d; branchProbability(0.99, j > -4); j -= 2) { + c += c + j & 0x3; + } + return c; + } + + @Test + public void testSumDownBy2() { + test("testSumDownBy2Snippet", 1); + for (int i = 0; i < 160; i++) { + test("testSumDownBy2Snippet", i); + } + } + @Test public void testLoopCarried() { test("testLoopCarriedSnippet", 1, 2); + test("testLoopCarriedSnippet", 0, 4); + test("testLoopCarriedSnippet", 4, 0); } public static int testLoopCarriedSnippet(int a, int b) { int c = a; int d = b; - for (int j = 0; j < a; j++) { + for (int j = 0; branchProbability(0.99, j < a); j++) { d = c; c += 1; } @@ -136,4 +169,16 @@ test("testComplexSnippet", 1000); } + public static long testSignExtensionSnippet(long arg) { + long r = 1; + for (int i = 0; branchProbability(0.99, i < arg); i++) { + r *= i; + } + return r; + } + + @Test + public void testSignExtension() { + test("testSignExtensionSnippet", 9L); + } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java 2017-08-03 22:42:50.070398371 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java 2017-08-03 22:42:49.972393977 -0700 @@ -22,15 +22,13 @@ */ package org.graalvm.compiler.loop; -import java.util.Collection; -import java.util.LinkedList; -import java.util.Queue; - +import jdk.vm.ci.code.BytecodeFrame; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeBitMap; import org.graalvm.compiler.graph.iterators.NodePredicate; @@ -72,7 +70,9 @@ import org.graalvm.util.EconomicSet; import org.graalvm.util.Equivalence; -import jdk.vm.ci.code.BytecodeFrame; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Queue; public class LoopEx { private final Loop loop; @@ -164,33 +164,46 @@ private class InvariantPredicate implements NodePredicate { + private final Graph.Mark mark; + + InvariantPredicate() { + this.mark = loopBegin().graph().getMark(); + } + @Override public boolean apply(Node n) { + if (loopBegin().graph().isNew(mark, n)) { + // Newly created nodes are unknown. + return false; + } return isOutsideLoop(n); } } - public void reassociateInvariants() { - InvariantPredicate invariant = new InvariantPredicate(); + public boolean reassociateInvariants() { + int count = 0; StructuredGraph graph = loopBegin().graph(); + InvariantPredicate invariant = new InvariantPredicate(); for (BinaryArithmeticNode binary : whole().nodes().filter(BinaryArithmeticNode.class)) { if (!binary.isAssociative()) { continue; } ValueNode result = BinaryArithmeticNode.reassociate(binary, invariant, binary.getX(), binary.getY()); if (result != binary) { - DebugContext debug = graph.getDebug(); - if (debug.isLogEnabled()) { - debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result); - } if (!result.isAlive()) { assert !result.isDeleted(); result = graph.addOrUniqueWithInputs(result); } + DebugContext debug = graph.getDebug(); + if (debug.isLogEnabled()) { + debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result); + } binary.replaceAtUsages(result); GraphUtil.killWithUnusedFloatingInputs(binary); + count++; } } + return count != 0; } public boolean detectCounted() { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java 2017-08-03 22:42:50.409413568 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java 2017-08-03 22:42:50.312409220 -0700 @@ -22,11 +22,7 @@ */ package org.graalvm.compiler.loop; -import java.util.ArrayDeque; -import java.util.Collections; -import java.util.Deque; -import java.util.Iterator; - +import jdk.vm.ci.meta.TriState; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; @@ -57,7 +53,10 @@ import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.util.EconomicMap; -import jdk.vm.ci.meta.TriState; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.Iterator; public abstract class LoopFragment { @@ -78,7 +77,10 @@ this.nodesReady = false; } - public LoopEx loop() { + /** + * Return the original LoopEx for this fragment. For duplicated fragments this returns null. + */ + protected LoopEx loop() { return loop; } @@ -172,6 +174,8 @@ NodeIterable nodesIterable = original().nodes(); duplicationMap = graph().addDuplicates(nodesIterable, graph(), nodesIterable.count(), dr); finishDuplication(); + nodes = new NodeBitMap(graph()); + nodes.markAll(duplicationMap.getValues()); nodesReady = true; } else { // TODO (gd) apply fix ? --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java 2017-08-03 22:42:50.744428587 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java 2017-08-03 22:42:50.645424149 -0700 @@ -22,9 +22,7 @@ */ package org.graalvm.compiler.loop; -import java.util.LinkedList; -import java.util.List; - +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; import org.graalvm.compiler.graph.Node; @@ -34,25 +32,37 @@ import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.GuardPhiNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.ProxyNode; +import org.graalvm.compiler.nodes.SafepointNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValuePhiNode; import org.graalvm.compiler.nodes.VirtualState.NodeClosure; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.SubNode; import org.graalvm.compiler.nodes.memory.MemoryPhiNode; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.util.EconomicMap; import org.graalvm.util.Equivalence; +import java.util.LinkedList; +import java.util.List; + public class LoopFragmentInside extends LoopFragment { /** @@ -133,9 +143,126 @@ } public void insertWithinAfter(LoopEx loop) { - assert this.isDuplicate() && this.original().loop() == loop; + assert isDuplicate() && original().loop() == loop; patchNodes(dataFixWithinAfter); + + LoopBeginNode mainLoopBegin = loop.loopBegin(); + for (PhiNode mainPhiNode : mainLoopBegin.phis()) { + ValueNode duplicatedNode = getDuplicatedNode(mainPhiNode.valueAt(1)); + if (duplicatedNode != null) { + mainPhiNode.setValueAt(1, duplicatedNode); + } else { + assert mainLoopBegin.isPhiAtMerge(mainPhiNode.valueAt(1)); + } + } + + placeNewSegmentAndCleanup(loop); + + // Remove any safepoints from the original copy leaving only the duplicated one + assert loop.whole().nodes().filter(SafepointNode.class).count() == nodes().filter(SafepointNode.class).count(); + for (SafepointNode safepoint : loop.whole().nodes().filter(SafepointNode.class)) { + GraphUtil.removeFixedWithUnusedInputs(safepoint); + } + + int unrollFactor = mainLoopBegin.getUnrollFactor(); + + // Now use the previous unrollFactor to update the exit condition to power of two + StructuredGraph graph = mainLoopBegin.graph(); + InductionVariable iv = loop.counted().getCounter(); + CompareNode compareNode = (CompareNode) loop.counted().getLimitTest().condition(); + ValueNode compareBound; + if (compareNode.getX() == iv.valueNode()) { + compareBound = compareNode.getY(); + } else if (compareNode.getY() == iv.valueNode()) { + compareBound = compareNode.getX(); + } else { + throw GraalError.shouldNotReachHere(); + } + if (iv.direction() == InductionVariable.Direction.Up) { + ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * iv.constantStride())); + ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal)); + compareNode.replaceFirstInput(compareBound, newLimit); + } else if (iv.direction() == InductionVariable.Direction.Down) { + ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * -iv.constantStride())); + ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal)); + compareNode.replaceFirstInput(compareBound, newLimit); + } + mainLoopBegin.setUnrollFactor(unrollFactor * 2); + mainLoopBegin.setLoopFrequency(mainLoopBegin.loopFrequency() / 2); + graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "LoopPartialUnroll %s", loop); + + mainLoopBegin.getDebug().dump(DebugContext.VERBOSE_LEVEL, mainLoopBegin.graph(), "After insertWithinAfter %s", mainLoopBegin); + } + + private void placeNewSegmentAndCleanup(LoopEx loop) { + CountedLoopInfo mainCounted = loop.counted(); + LoopBeginNode mainLoopBegin = loop.loopBegin(); + // Discard the segment entry and its flow, after if merging it into the loop + StructuredGraph graph = mainLoopBegin.graph(); + IfNode loopTest = mainCounted.getLimitTest(); + IfNode newSegmentTest = getDuplicatedNode(loopTest); + AbstractBeginNode trueSuccessor = loopTest.trueSuccessor(); + AbstractBeginNode falseSuccessor = loopTest.falseSuccessor(); + FixedNode firstNode; + boolean codeInTrueSide = false; + if (trueSuccessor == mainCounted.getBody()) { + firstNode = trueSuccessor.next(); + codeInTrueSide = true; + } else { + assert (falseSuccessor == mainCounted.getBody()); + firstNode = falseSuccessor.next(); + } + trueSuccessor = newSegmentTest.trueSuccessor(); + falseSuccessor = newSegmentTest.falseSuccessor(); + for (Node usage : falseSuccessor.anchored().snapshot()) { + usage.replaceFirstInput(falseSuccessor, loopTest.falseSuccessor()); + } + for (Node usage : trueSuccessor.anchored().snapshot()) { + usage.replaceFirstInput(trueSuccessor, loopTest.trueSuccessor()); + } + AbstractBeginNode startBlockNode; + if (codeInTrueSide) { + startBlockNode = trueSuccessor; + } else { + graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, mainLoopBegin.graph(), "before"); + startBlockNode = falseSuccessor; + } + FixedNode lastNode = getBlockEnd(startBlockNode); + LoopEndNode loopEndNode = mainLoopBegin.getSingleLoopEnd(); + FixedWithNextNode lastCodeNode = (FixedWithNextNode) loopEndNode.predecessor(); + FixedNode newSegmentFirstNode = getDuplicatedNode(firstNode); + FixedWithNextNode newSegmentLastNode = getDuplicatedNode(lastCodeNode); + graph.getDebug().dump(DebugContext.DETAILED_LEVEL, loopEndNode.graph(), "Before placing segment"); + if (firstNode instanceof LoopEndNode) { + GraphUtil.killCFG(getDuplicatedNode(mainLoopBegin)); + } else { + newSegmentLastNode.clearSuccessors(); + startBlockNode.setNext(lastNode); + lastCodeNode.replaceFirstSuccessor(loopEndNode, newSegmentFirstNode); + newSegmentLastNode.replaceFirstSuccessor(lastNode, loopEndNode); + lastCodeNode.setNext(newSegmentFirstNode); + newSegmentLastNode.setNext(loopEndNode); + startBlockNode.clearSuccessors(); + lastNode.safeDelete(); + Node newSegmentTestStart = newSegmentTest.predecessor(); + LogicNode newSegmentIfTest = newSegmentTest.condition(); + newSegmentTestStart.clearSuccessors(); + newSegmentTest.safeDelete(); + newSegmentIfTest.safeDelete(); + trueSuccessor.safeDelete(); + falseSuccessor.safeDelete(); + newSegmentTestStart.safeDelete(); + } + graph.getDebug().dump(DebugContext.DETAILED_LEVEL, loopEndNode.graph(), "After placing segment"); + } + + private static EndNode getBlockEnd(FixedNode node) { + FixedNode curNode = node; + while (curNode instanceof FixedWithNextNode) { + curNode = ((FixedWithNextNode) curNode).next(); + } + return (EndNode) curNode; } @Override --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java 2017-08-03 22:42:51.089444054 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java 2017-08-03 22:42:50.991439660 -0700 @@ -300,6 +300,16 @@ return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this; } + public LoopExitNode getSingleLoopExit() { + assert loopExits().count() == 1; + return loopExits().first(); + } + + public LoopEndNode getSingleLoopEnd() { + assert loopEnds().count() == 1; + return loopEnds().first(); + } + public void removeExits() { for (LoopExitNode loopexit : loopExits().snapshot()) { loopexit.removeProxies(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java 2017-08-03 22:42:51.427459207 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java 2017-08-03 22:42:51.328454769 -0700 @@ -35,7 +35,7 @@ import org.graalvm.compiler.nodes.spi.ValueProxy; @NodeInfo(cycles = CYCLES_0, size = SIZE_0) -public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy, GuardingNode { +public class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy, GuardingNode { public static final NodeClass TYPE = NodeClass.create(FixedValueAnchorNode.class); @Input ValueNode object; @@ -45,11 +45,15 @@ return object; } - public FixedValueAnchorNode(ValueNode object) { - super(TYPE, object.stamp()); + protected FixedValueAnchorNode(NodeClass c, ValueNode object) { + super(c, object.stamp()); this.object = object; } + public FixedValueAnchorNode(ValueNode object) { + this(TYPE, object); + } + public FixedValueAnchorNode(ValueNode object, Stamp predefinedStamp) { super(TYPE, predefinedStamp); this.object = object; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java 2017-08-03 22:42:51.757474001 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java 2017-08-03 22:42:51.659469608 -0700 @@ -39,6 +39,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.word.LocationIdentity; @@ -124,7 +125,7 @@ int entryIndex = virtual.entryIndexForOffset(off, accessKind()); if (entryIndex != -1) { JavaKind entryKind = virtual.entryKind(entryIndex); - boolean canVirtualize = entryKind == accessKind() || entryKind == accessKind().getStackKind(); + boolean canVirtualize = entryKind == accessKind() || (entryKind == accessKind().getStackKind() && !StampTool.typeOrNull(object()).isArray()); if (!canVirtualize) { /* * Special case: If the entryKind is long, allow arbitrary kinds as long as --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java 2017-08-03 22:42:52.101489423 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java 2017-08-03 22:42:51.999484850 -0700 @@ -1092,7 +1092,7 @@ static final Class[][] SIGS; static { - if (!Assertions.ENABLED) { + if (!Assertions.assertionsEnabled()) { throw new GraalError("%s must only be used in assertions", Checks.class.getName()); } ArrayList[]> sigs = new ArrayList<>(MAX_ARITY); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java 2017-08-03 22:42:52.446504890 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java 2017-08-03 22:42:52.346500407 -0700 @@ -90,7 +90,7 @@ @Override public boolean inferStamp() { - return updateStamp(createStamp(graph().getAssumptions(), array(), elementKind())); + return updateStamp(stamp.improveWith(createStamp(graph().getAssumptions(), array(), elementKind()))); } @Override @@ -101,7 +101,13 @@ ValueNode indexValue = tool.getAlias(index()); int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1; if (idx >= 0 && idx < virtual.entryCount()) { - tool.replaceWith(tool.getEntry(virtual, idx)); + ValueNode entry = tool.getEntry(virtual, idx); + if (stamp.isCompatible(entry.stamp())) { + tool.replaceWith(entry); + } else { + assert stamp().getStackKind() == JavaKind.Int && (entry.stamp().getStackKind() == JavaKind.Long || entry.getStackKind() == JavaKind.Double || + entry.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one stot fields."; + } } } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java 2017-08-03 22:42:52.792520402 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java 2017-08-03 22:42:52.691515874 -0700 @@ -28,10 +28,12 @@ package org.graalvm.compiler.options.test; +import static org.graalvm.compiler.options.OptionValues.asMap; import static org.graalvm.compiler.options.test.TestOptionKey.Options.MyOption; import static org.graalvm.compiler.options.test.TestOptionKey.Options.MyOtherOption; import static org.junit.Assert.assertEquals; +import org.graalvm.compiler.options.ModifiableOptionValues; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; @@ -65,4 +67,20 @@ } Assert.assertTrue(sawAssertionError); } + + /** + * Tests that initial values are properly copied. + */ + @Test + public void testDerived() { + OptionValues initialOptions = new ModifiableOptionValues(asMap(MyOption, "new value 1")); + OptionValues derivedOptions = new OptionValues(initialOptions, MyOtherOption, "ignore"); + Assert.assertEquals("new value 1", MyOption.getValue(derivedOptions)); + + initialOptions = new OptionValues(asMap(MyOption, "new value 1")); + derivedOptions = new OptionValues(initialOptions, MyOtherOption, "ignore"); + Assert.assertEquals("new value 1", MyOption.getValue(derivedOptions)); + + } + } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java 2017-08-03 22:42:53.129535510 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java 2017-08-03 22:42:53.030531072 -0700 @@ -48,7 +48,16 @@ } /** + * Value that can be used in {@link #update(UnmodifiableEconomicMap)} and + * {@link #update(OptionKey, Object)} to remove an explicitly set value for a key such that + * {@link OptionKey#hasBeenSet(OptionValues)} will return {@code false} for the key. + */ + public static final Object UNSET_KEY = new Object(); + + /** * Updates this object with the given key/value pair. + * + * @see #UNSET_KEY */ public void update(OptionKey key, Object value) { UnmodifiableEconomicMap, Object> expect; @@ -56,14 +65,20 @@ do { expect = v.get(); newMap = EconomicMap.create(Equivalence.IDENTITY, expect); - key.update(newMap, value); - // Need to do the null encoding here as `key.update()` doesn't do it - newMap.put(key, encodeNull(value)); + if (value == UNSET_KEY) { + newMap.removeKey(key); + } else { + key.update(newMap, value); + // Need to do the null encoding here as `key.update()` doesn't do it + newMap.put(key, encodeNull(value)); + } } while (!v.compareAndSet(expect, newMap)); } /** * Updates this object with the key/value pairs in {@code values}. + * + * @see #UNSET_KEY */ public void update(UnmodifiableEconomicMap, Object> values) { if (values.isEmpty()) { @@ -78,9 +93,13 @@ while (cursor.advance()) { OptionKey key = cursor.getKey(); Object value = cursor.getValue(); - key.update(newMap, value); - // Need to do the null encoding here as `key.update()` doesn't do it - newMap.put(key, encodeNull(value)); + if (value == UNSET_KEY) { + newMap.removeKey(key); + } else { + key.update(newMap, value); + // Need to do the null encoding here as `key.update()` doesn't do it + newMap.put(key, encodeNull(value)); + } } } while (!v.compareAndSet(expect, newMap)); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java 2017-08-03 22:42:53.462550440 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java 2017-08-03 22:42:53.364546046 -0700 @@ -52,7 +52,7 @@ public OptionValues(OptionValues initialValues, UnmodifiableEconomicMap, Object> extraPairs) { EconomicMap, Object> map = newOptionMap(); if (initialValues != null) { - map.putAll(initialValues.values); + map.putAll(initialValues.getMap()); } initMap(map, extraPairs); this.values = map; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java 2017-08-03 22:42:53.804565772 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java 2017-08-03 22:42:53.702561199 -0700 @@ -101,15 +101,12 @@ private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) { AbstractBeginNode trueTarget = ifNode.trueSuccessor(); AbstractBeginNode falseTarget = ifNode.falseSuccessor(); - double firstIfProbability = shortCircuitProbability; - /* - * P(Y | not(X)) = P(Y inter not(X)) / P(not(X)) = (P(X union Y) - P(X)) / (1 - P(X)) - * - * P(X) = shortCircuitProbability - * - * P(X union Y) = ifNode.probability(trueTarget) - */ - double secondIfProbability = (ifNode.probability(trueTarget) - shortCircuitProbability) / (1 - shortCircuitProbability); + // while the first if node is reached by all cases, the true values are split between the + // first and the second if + double firstIfProbability = ifNode.probability(trueTarget) * shortCircuitProbability; + // the second if node is reached by a reduced number of true cases but the same number of + // false cases + double secondIfProbability = 1 - ifNode.probability(falseTarget) / (1 - firstIfProbability); secondIfProbability = Math.min(1.0, Math.max(0.0, secondIfProbability)); if (Double.isNaN(secondIfProbability)) { secondIfProbability = 0.5; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java 2017-08-03 22:42:54.142580925 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java 2017-08-03 22:42:54.043576487 -0700 @@ -35,6 +35,7 @@ import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.CompressionNode; import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; import org.graalvm.compiler.nodes.DynamicDeoptimizeNode; @@ -197,6 +198,14 @@ AddressNode address = fixedAccessNode.getAddress(); ValueNode base = address.getBase(); ValueNode index = address.getIndex(); + // allow for architectures which cannot fold an + // intervening uncompress out of the address chain + if (base != null && base instanceof CompressionNode) { + base = ((CompressionNode) base).getValue(); + } + if (index != null && index instanceof CompressionNode) { + index = ((CompressionNode) index).getValue(); + } if (((base == value && index == null) || (base == null && index == value)) && address.getMaxConstantDisplacement() < implicitNullCheckLimit) { // Opportunity for implicit null check as part of an existing read found! fixedAccessNode.setStateBefore(deopt.stateBefore()); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java 2017-08-03 22:42:54.486596347 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java 2017-08-03 22:42:54.386591864 -0700 @@ -86,23 +86,23 @@ public static class BasePhaseStatistics { /** - * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}. + * Records time spent in {@link BasePhase#apply(StructuredGraph, Object, boolean)}. */ private final TimerKey timer; /** - * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}. + * Counts calls to {@link BasePhase#apply(StructuredGraph, Object, boolean)}. */ private final CounterKey executionCount; /** * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to - * {@link #apply(StructuredGraph, Object, boolean)}. + * {@link BasePhase#apply(StructuredGraph, Object, boolean)}. */ private final CounterKey inputNodesCount; /** - * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}. + * Records memory usage within {@link BasePhase#apply(StructuredGraph, Object, boolean)}. */ private final MemUseTrackerKey memUseTracker; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java 2017-08-03 22:42:54.822611411 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java 2017-08-03 22:42:54.722606928 -0700 @@ -30,7 +30,6 @@ import java.util.Formatter; import java.util.List; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.cfg.BlockMap; @@ -107,7 +106,7 @@ } private NodeEventScope verifyImmutableGraph(StructuredGraph graph) { - if (immutableGraph && Assertions.ENABLED) { + if (immutableGraph && Assertions.assertionsEnabled()) { return graph.trackNodeEvents(new NodeEventListener() { @Override public void event(NodeEvent e, Node node) { @@ -178,7 +177,7 @@ sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited); assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap); - assert (!GraalOptions.DetailedAsserts.getValue(graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap); + assert (!Assertions.detailedAssertionsEnabled(graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap); this.blockToNodesMap = latestBlockToNodesMap; @@ -880,7 +879,7 @@ } } - assert (!GraalOptions.DetailedAsserts.getValue(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes); + assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes); } private static void processStackPhi(NodeStack stack, PhiNode phiNode, NodeMap nodeToBlock, NodeBitMap visited) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java 2017-08-03 22:42:55.169626968 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java 2017-08-03 22:42:55.071622574 -0700 @@ -26,21 +26,18 @@ import static org.graalvm.compiler.graph.Edges.Type.Successors; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; -import java.nio.charset.Charset; import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashMap; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import jdk.vm.ci.meta.ResolvedJavaField; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.core.common.cfg.BlockMap; -import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.graph.CachedGraph; import org.graalvm.compiler.graph.Edges; @@ -48,7 +45,6 @@ import org.graalvm.compiler.graph.InputEdges; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.NodeList; import org.graalvm.compiler.graph.NodeMap; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; @@ -59,107 +55,33 @@ import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.ProxyNode; -import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; import org.graalvm.compiler.nodes.VirtualState; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; - -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; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.NodeSourcePosition; - -public class BinaryGraphPrinter implements GraphPrinter { - - private static final int CONSTANT_POOL_MAX_SIZE = 8000; - - private static final int BEGIN_GROUP = 0x00; - private static final int BEGIN_GRAPH = 0x01; - private static final int CLOSE_GROUP = 0x02; - - private static final int POOL_NEW = 0x00; - private static final int POOL_STRING = 0x01; - private static final int POOL_ENUM = 0x02; - private static final int POOL_CLASS = 0x03; - private static final int POOL_METHOD = 0x04; - private static final int POOL_NULL = 0x05; - private static final int POOL_NODE_CLASS = 0x06; - private static final int POOL_FIELD = 0x07; - private static final int POOL_SIGNATURE = 0x08; - private static final int POOL_NODE_SOURCE_POSITION = 0x09; - - private static final int PROPERTY_POOL = 0x00; - private static final int PROPERTY_INT = 0x01; - private static final int PROPERTY_LONG = 0x02; - private static final int PROPERTY_DOUBLE = 0x03; - private static final int PROPERTY_FLOAT = 0x04; - private static final int PROPERTY_TRUE = 0x05; - private static final int PROPERTY_FALSE = 0x06; - private static final int PROPERTY_ARRAY = 0x07; - private static final int PROPERTY_SUBGRAPH = 0x08; - - private static final int KLASS = 0x00; - private static final int ENUM_KLASS = 0x01; - - static final int CURRENT_MAJOR_VERSION = 4; - static final int CURRENT_MINOR_VERSION = 0; - - static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'}; - - private void writeVersion() throws IOException { - writeBytesRaw(MAGIC_BYTES); - writeByte(CURRENT_MAJOR_VERSION); - writeByte(CURRENT_MINOR_VERSION); - } - - private static final class ConstantPool extends LinkedHashMap { - - private final LinkedList availableIds; - private char nextId; - private static final long serialVersionUID = -2676889957907285681L; - - ConstantPool() { - super(50, 0.65f); - availableIds = new LinkedList<>(); - } - - @Override - protected boolean removeEldestEntry(java.util.Map.Entry eldest) { - if (size() > CONSTANT_POOL_MAX_SIZE) { - availableIds.addFirst(eldest.getValue()); - return true; - } - return false; - } - - private Character nextAvailableId() { - if (!availableIds.isEmpty()) { - return availableIds.removeFirst(); - } - return nextId++; - } - - public char add(Object obj) { - Character id = nextAvailableId(); - put(obj, id); - return id; - } - } - - private final ConstantPool constantPool; - private final ByteBuffer buffer; - private final WritableByteChannel channel; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.graphio.GraphBlocks; +import org.graalvm.graphio.GraphElements; +import org.graalvm.graphio.GraphOutput; +import org.graalvm.graphio.GraphStructure; +import org.graalvm.graphio.GraphTypes; + +public class BinaryGraphPrinter implements + GraphStructure, Edges>, + GraphBlocks, + GraphElements, + GraphTypes, GraphPrinter { private final SnippetReflectionProvider snippetReflection; - - private static final Charset utf8 = Charset.forName("UTF-8"); + private final GraphOutput output; public BinaryGraphPrinter(WritableByteChannel channel, SnippetReflectionProvider snippetReflection) throws IOException { - constantPool = new ConstantPool(); + this.output = GraphOutput.newBuilder(this).blocks(this).elements(this).types(this).build(channel); this.snippetReflection = snippetReflection; - buffer = ByteBuffer.allocateDirect(256 * 1024); - this.channel = channel; - writeVersion(); } @Override @@ -167,341 +89,176 @@ return snippetReflection; } - @SuppressWarnings("all") @Override - public void print(DebugContext debug, Graph graph, Map properties, int id, String format, Object... args) throws IOException { - writeByte(BEGIN_GRAPH); - if (CURRENT_MAJOR_VERSION >= 3) { - writeInt(id); - writeString(format); - writeInt(args.length); - for (Object a : args) { - writePropertyObject(debug, a); - } + public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map properties) throws IOException { + output.beginGroup(new GraphInfo(debug, null), name, shortName, method, bci, properties); + } + + @Override + public void endGroup() throws IOException { + output.endGroup(); + } + + @Override + public void close() { + output.close(); + } + + @Override + public ResolvedJavaMethod method(Object object) { + if (object instanceof Bytecode) { + return ((Bytecode) object).getMethod(); + } else if (object instanceof ResolvedJavaMethod) { + return ((ResolvedJavaMethod) object); } else { - writePoolObject(id + ": " + String.format(format, simplifyClassArgs(args))); + return null; } - writeGraph(debug, graph, properties); - flush(); } - private void writeGraph(DebugContext debug, Graph graph, Map properties) throws IOException { - boolean needSchedule = DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null; - ScheduleResult scheduleResult = needSchedule ? GraphPrinter.getScheduleOrNull(graph) : null; - ControlFlowGraph cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG(); - BlockMap> blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap(); - NodeMap nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap(); - List blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks()); - writeProperties(debug, properties); - writeNodes(debug, graph, nodeToBlocks, cfg); - writeBlocks(blocks, blockToNodes); - } - - private void flush() throws IOException { - buffer.flip(); - /* - * Try not to let interrupted threads abort the write. There's still a race here but an - * interrupt that's been pending for a long time shouldn't stop this writing. - */ - boolean interrupted = Thread.interrupted(); - try { - channel.write(buffer); - } finally { - if (interrupted) { - Thread.currentThread().interrupt(); - } + @Override + public NodeClass nodeClass(Object obj) { + if (obj instanceof NodeClass) { + return (NodeClass) obj; + } + if (obj instanceof Node) { + return ((Node) obj).getNodeClass(); } - buffer.compact(); + return null; } - private void ensureAvailable(int i) throws IOException { - assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small"; - while (buffer.remaining() < i) { - flush(); - } + @Override + public Object nodeClassType(NodeClass node) { + return node.getJavaClass(); } - private void writeByte(int b) throws IOException { - ensureAvailable(1); - buffer.put((byte) b); + @Override + public String nameTemplate(NodeClass nodeClass) { + return nodeClass.getNameTemplate(); } - private void writeInt(int b) throws IOException { - ensureAvailable(4); - buffer.putInt(b); + @Override + public final GraphInfo graph(GraphInfo currrent, Object obj) { + if (obj instanceof Graph) { + return new GraphInfo(currrent.debug, (Graph) obj); + } else if (obj instanceof CachedGraph) { + return new GraphInfo(currrent.debug, ((CachedGraph) obj).getReadonlyCopy()); + } else { + return null; + } } - private void writeLong(long b) throws IOException { - ensureAvailable(8); - buffer.putLong(b); + @Override + public int nodeId(Node n) { + return getNodeId(n); } - private void writeDouble(double b) throws IOException { - ensureAvailable(8); - buffer.putDouble(b); + @Override + public Edges portInputs(NodeClass nodeClass) { + return nodeClass.getEdges(Inputs); } - private void writeFloat(float b) throws IOException { - ensureAvailable(4); - buffer.putFloat(b); + @Override + public Edges portOutputs(NodeClass nodeClass) { + return nodeClass.getEdges(Successors); } - private void writeShort(char b) throws IOException { - ensureAvailable(2); - buffer.putChar(b); + @SuppressWarnings("deprecation") + private static int getNodeId(Node node) { + return node == null ? -1 : node.getId(); } - private void writeString(String str) throws IOException { - byte[] bytes = str.getBytes(utf8); - writeBytes(bytes); + @Override + public List blockNodes(GraphInfo info, Block block) { + List nodes = info.blockToNodes.get(block); + if (nodes == null) { + return null; + } + List extraNodes = new LinkedList<>(); + for (Node node : nodes) { + findExtraNodes(node, extraNodes); + } + extraNodes.removeAll(nodes); + extraNodes.addAll(0, nodes); + return extraNodes; } - private void writeBytes(byte[] b) throws IOException { - if (b == null) { - writeInt(-1); - } else { - writeInt(b.length); - writeBytesRaw(b); - } + @Override + public int blockId(Block sux) { + return sux.getId(); } - private void writeBytesRaw(byte[] b) throws IOException { - int bytesWritten = 0; - while (bytesWritten < b.length) { - int toWrite = Math.min(b.length - bytesWritten, buffer.capacity()); - ensureAvailable(toWrite); - buffer.put(b, bytesWritten, toWrite); - bytesWritten += toWrite; - } + @Override + public List blockSuccessors(Block block) { + return Arrays.asList(block.getSuccessors()); } - private void writeInts(int[] b) throws IOException { - if (b == null) { - writeInt(-1); - } else { - writeInt(b.length); - int sizeInBytes = b.length * 4; - ensureAvailable(sizeInBytes); - buffer.asIntBuffer().put(b); - buffer.position(buffer.position() + sizeInBytes); - } + @Override + public Iterable nodes(GraphInfo info) { + return info.graph.getNodes(); } - private void writeDoubles(double[] b) throws IOException { - if (b == null) { - writeInt(-1); - } else { - writeInt(b.length); - int sizeInBytes = b.length * 8; - ensureAvailable(sizeInBytes); - buffer.asDoubleBuffer().put(b); - buffer.position(buffer.position() + sizeInBytes); - } + @Override + public int nodesCount(GraphInfo info) { + return info.graph.getNodeCount(); } - private void writePoolObject(Object object) throws IOException { - if (object == null) { - writeByte(POOL_NULL); - return; - } - Character id = constantPool.get(object); - if (id == null) { - addPoolEntry(object); - } else { - if (object instanceof Enum) { - writeByte(POOL_ENUM); - } else if (object instanceof Class || object instanceof JavaType) { - writeByte(POOL_CLASS); - } else if (object instanceof NodeClass) { - writeByte(POOL_NODE_CLASS); - } else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) { - writeByte(POOL_METHOD); - } else if (object instanceof ResolvedJavaField) { - writeByte(POOL_FIELD); - } else if (object instanceof Signature) { - writeByte(POOL_SIGNATURE); - } else if (CURRENT_MAJOR_VERSION >= 4 && object instanceof NodeSourcePosition) { - writeByte(POOL_NODE_SOURCE_POSITION); - } else { - writeByte(POOL_STRING); + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void nodeProperties(GraphInfo info, Node node, Map props) { + node.getDebugProperties((Map) props); + Graph graph = info.graph; + ControlFlowGraph cfg = info.cfg; + NodeMap nodeToBlocks = info.nodeToBlocks; + if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) { + try { + props.put("probability", cfg.blockFor(node).probability()); + } catch (Throwable t) { + props.put("probability", 0.0); + props.put("probability-exception", t); } - writeShort(id.charValue()); } - } - private static String getClassName(Class klass) { - if (!klass.isArray()) { - return klass.getName(); - } - return getClassName(klass.getComponentType()) + "[]"; - } - - @SuppressWarnings("all") - private void addPoolEntry(Object object) throws IOException { - char index = constantPool.add(object); - writeByte(POOL_NEW); - writeShort(index); - if (object instanceof Class) { - Class klass = (Class) object; - writeByte(POOL_CLASS); - writeString(getClassName(klass)); - if (klass.isEnum()) { - writeByte(ENUM_KLASS); - Object[] enumConstants = klass.getEnumConstants(); - writeInt(enumConstants.length); - for (Object o : enumConstants) { - writePoolObject(((Enum) o).name()); - } - } else { - writeByte(KLASS); - } - } else if (object instanceof Enum) { - writeByte(POOL_ENUM); - writePoolObject(object.getClass()); - writeInt(((Enum) object).ordinal()); - } else if (object instanceof JavaType) { - JavaType type = (JavaType) object; - writeByte(POOL_CLASS); - writeString(type.toJavaName()); - writeByte(KLASS); - } else if (object instanceof NodeClass) { - NodeClass nodeClass = (NodeClass) object; - writeByte(POOL_NODE_CLASS); - if (CURRENT_MAJOR_VERSION >= 3) { - writePoolObject(nodeClass.getJavaClass()); - writeString(nodeClass.getNameTemplate()); - } else { - writeString(nodeClass.getJavaClass().getSimpleName()); - String nameTemplate = nodeClass.getNameTemplate(); - writeString(nameTemplate.isEmpty() ? nodeClass.shortName() : nameTemplate); - } - writeEdgesInfo(nodeClass, Inputs); - writeEdgesInfo(nodeClass, Successors); - } else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) { - writeByte(POOL_METHOD); - ResolvedJavaMethod method; - if (object instanceof Bytecode) { - method = ((Bytecode) object).getMethod(); - } else { - method = ((ResolvedJavaMethod) object); - } - writePoolObject(method.getDeclaringClass()); - writePoolObject(method.getName()); - writePoolObject(method.getSignature()); - writeInt(method.getModifiers()); - writeBytes(method.getCode()); - } else if (object instanceof ResolvedJavaField) { - writeByte(POOL_FIELD); - ResolvedJavaField field = ((ResolvedJavaField) object); - writePoolObject(field.getDeclaringClass()); - writePoolObject(field.getName()); - writePoolObject(field.getType().getName()); - writeInt(field.getModifiers()); - } else if (object instanceof Signature) { - writeByte(POOL_SIGNATURE); - Signature signature = ((Signature) object); - int args = signature.getParameterCount(false); - writeShort((char) args); - for (int i = 0; i < args; i++) { - writePoolObject(signature.getParameterType(i, null).getName()); - } - writePoolObject(signature.getReturnType(null).getName()); - } else if (CURRENT_MAJOR_VERSION >= 4 && object instanceof NodeSourcePosition) { - writeByte(POOL_NODE_SOURCE_POSITION); - NodeSourcePosition pos = (NodeSourcePosition) object; - ResolvedJavaMethod method = pos.getMethod(); - writePoolObject(method); - final int bci = pos.getBCI(); - writeInt(bci); - StackTraceElement ste = method.asStackTraceElement(bci); - if (ste != null) { - String fn = ste.getFileName(); - writePoolObject(fn); - if (fn != null) { - writeInt(ste.getLineNumber()); - } - } else { - writePoolObject(null); - } - writePoolObject(pos.getCaller()); - } else { - writeByte(POOL_STRING); - writeString(object.toString()); + try { + props.put("NodeCost-Size", node.estimatedNodeSize()); + props.put("NodeCost-Cycles", node.estimatedNodeCycles()); + } catch (Throwable t) { + props.put("node-cost-exception", t.getMessage()); } - } - private void writeEdgesInfo(NodeClass nodeClass, Edges.Type type) throws IOException { - Edges edges = nodeClass.getEdges(type); - writeShort((char) edges.getCount()); - for (int i = 0; i < edges.getCount(); i++) { - writeByte(i < edges.getDirectCount() ? 0 : 1); - writePoolObject(edges.getName(i)); - if (type == Inputs) { - writePoolObject(((InputEdges) edges).getInputType(i)); + if (nodeToBlocks != null) { + Object block = getBlockForNode(node, nodeToBlocks); + if (block != null) { + props.put("node-to-block", block); } } - } - private void writePropertyObject(DebugContext debug, Object obj) throws IOException { - if (obj instanceof Integer) { - writeByte(PROPERTY_INT); - writeInt(((Integer) obj).intValue()); - } else if (obj instanceof Long) { - writeByte(PROPERTY_LONG); - writeLong(((Long) obj).longValue()); - } else if (obj instanceof Double) { - writeByte(PROPERTY_DOUBLE); - writeDouble(((Double) obj).doubleValue()); - } else if (obj instanceof Float) { - writeByte(PROPERTY_FLOAT); - writeFloat(((Float) obj).floatValue()); - } else if (obj instanceof Boolean) { - if (((Boolean) obj).booleanValue()) { - writeByte(PROPERTY_TRUE); - } else { - writeByte(PROPERTY_FALSE); - } - } else if (obj instanceof Graph) { - writeByte(PROPERTY_SUBGRAPH); - writeGraph(debug, (Graph) obj, null); - } else if (obj instanceof CachedGraph) { - writeByte(PROPERTY_SUBGRAPH); - writeGraph(debug, ((CachedGraph) obj).getReadonlyCopy(), null); - } else if (obj != null && obj.getClass().isArray()) { - Class componentType = obj.getClass().getComponentType(); - if (componentType.isPrimitive()) { - if (componentType == Double.TYPE) { - writeByte(PROPERTY_ARRAY); - writeByte(PROPERTY_DOUBLE); - writeDoubles((double[]) obj); - } else if (componentType == Integer.TYPE) { - writeByte(PROPERTY_ARRAY); - writeByte(PROPERTY_INT); - writeInts((int[]) obj); - } else { - writeByte(PROPERTY_POOL); - writePoolObject(obj); - } - } else { - writeByte(PROPERTY_ARRAY); - writeByte(PROPERTY_POOL); - Object[] array = (Object[]) obj; - writeInt(array.length); - for (Object o : array) { - writePoolObject(o); - } - } + if (node instanceof ControlSinkNode) { + props.put("category", "controlSink"); + } else if (node instanceof ControlSplitNode) { + props.put("category", "controlSplit"); + } else if (node instanceof AbstractMergeNode) { + props.put("category", "merge"); + } else if (node instanceof AbstractBeginNode) { + props.put("category", "begin"); + } else if (node instanceof AbstractEndNode) { + props.put("category", "end"); + } else if (node instanceof FixedNode) { + props.put("category", "fixed"); + } else if (node instanceof VirtualState) { + props.put("category", "state"); + } else if (node instanceof PhiNode) { + props.put("category", "phi"); + } else if (node instanceof ProxyNode) { + props.put("category", "proxy"); } else { - writeByte(PROPERTY_POOL); - writePoolObject(obj); + if (node instanceof ConstantNode) { + ConstantNode cn = (ConstantNode) node; + updateStringPropertiesForConstant((Map) props, cn); + } + props.put("category", "floating"); } } - @SuppressWarnings("deprecation") - private static int getNodeId(Node node) { - return node.getId(); - } - private Object getBlockForNode(Node node, NodeMap nodeToBlocks) { if (nodeToBlocks.isNew(node)) { return "NEW (not in schedule)"; @@ -516,181 +273,243 @@ return null; } - private void writeNodes(DebugContext debug, Graph graph, NodeMap nodeToBlocks, ControlFlowGraph cfg) throws IOException { - Map props = new HashMap<>(); + private static void findExtraNodes(Node node, Collection extraNodes) { + if (node instanceof AbstractMergeNode) { + AbstractMergeNode merge = (AbstractMergeNode) node; + for (PhiNode phi : merge.phis()) { + extraNodes.add(phi); + } + } + } - writeInt(graph.getNodeCount()); + @Override + public boolean nodeHasPredecessor(Node node) { + return node.predecessor() != null; + } - for (Node node : graph.getNodes()) { - NodeClass nodeClass = node.getNodeClass(); - node.getDebugProperties(props); - if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) { - try { - props.put("probability", cfg.blockFor(node).probability()); - } catch (Throwable t) { - props.put("probability", 0.0); - props.put("probability-exception", t); - } - } + @Override + public List blocks(GraphInfo graph) { + return graph.blocks; + } - try { - props.put("NodeCost-Size", node.estimatedNodeSize()); - props.put("NodeCost-Cycles", node.estimatedNodeCycles()); - } catch (Throwable t) { - props.put("node-cost-exception", t.getMessage()); - } + @Override + public void print(DebugContext debug, Graph graph, Map properties, int id, String format, Object... args) throws IOException { + output.print(new GraphInfo(debug, graph), properties, id, format, args); + } - if (nodeToBlocks != null) { - Object block = getBlockForNode(node, nodeToBlocks); - if (block != null) { - props.put("node-to-block", block); - } - } + @Override + public int portSize(Edges port) { + return port.getCount(); + } - if (node instanceof ControlSinkNode) { - props.put("category", "controlSink"); - } else if (node instanceof ControlSplitNode) { - props.put("category", "controlSplit"); - } else if (node instanceof AbstractMergeNode) { - props.put("category", "merge"); - } else if (node instanceof AbstractBeginNode) { - props.put("category", "begin"); - } else if (node instanceof AbstractEndNode) { - props.put("category", "end"); - } else if (node instanceof FixedNode) { - props.put("category", "fixed"); - } else if (node instanceof VirtualState) { - props.put("category", "state"); - } else if (node instanceof PhiNode) { - props.put("category", "phi"); - } else if (node instanceof ProxyNode) { - props.put("category", "proxy"); - } else { - if (node instanceof ConstantNode) { - ConstantNode cn = (ConstantNode) node; - updateStringPropertiesForConstant(props, cn); - } - props.put("category", "floating"); - } + @Override + public boolean edgeDirect(Edges port, int index) { + return index < port.getDirectCount(); + } + + @Override + public String edgeName(Edges port, int index) { + return port.getName(index); + } + + @Override + public Object edgeType(Edges port, int index) { + return ((InputEdges) port).getInputType(index); + } - writeInt(getNodeId(node)); - writePoolObject(nodeClass); - writeByte(node.predecessor() == null ? 0 : 1); - writeProperties(debug, props); - writeEdges(node, Inputs); - writeEdges(node, Successors); - - props.clear(); + @Override + public Collection edgeNodes(GraphInfo graph, Node node, Edges port, int i) { + if (i < port.getDirectCount()) { + Node single = Edges.getNode(node, port.getOffsets(), i); + return Collections.singletonList(single); + } else { + return Edges.getNodeList(node, port.getOffsets(), i); } } - private void writeProperties(DebugContext debug, Map props) throws IOException { - if (props == null) { - writeShort((char) 0); - return; - } - // properties - writeShort((char) props.size()); - for (Entry entry : props.entrySet()) { - String key = entry.getKey().toString(); - writePoolObject(key); - writePropertyObject(debug, entry.getValue()); + @Override + public Object enumClass(Object enumValue) { + if (enumValue instanceof Enum) { + return enumValue.getClass(); } + return null; } - private void writeEdges(Node node, Edges.Type type) throws IOException { - NodeClass nodeClass = node.getNodeClass(); - Edges edges = nodeClass.getEdges(type); - final long[] curOffsets = edges.getOffsets(); - for (int i = 0; i < edges.getDirectCount(); i++) { - writeNodeRef(Edges.getNode(node, curOffsets, i)); - } - for (int i = edges.getDirectCount(); i < edges.getCount(); i++) { - NodeList list = Edges.getNodeList(node, curOffsets, i); - if (list == null) { - writeShort((char) 0); - } else { - int listSize = list.count(); - assert listSize == ((char) listSize); - writeShort((char) listSize); - for (Node edge : list) { - writeNodeRef(edge); + @Override + public int enumOrdinal(Object obj) { + if (obj instanceof Enum) { + return ((Enum) obj).ordinal(); + } + return -1; + } + + @SuppressWarnings("unchecked") + @Override + public String[] enumTypeValues(Object clazz) { + if (clazz instanceof Class) { + Class> enumClass = (Class>) clazz; + Enum[] constants = enumClass.getEnumConstants(); + if (constants != null) { + String[] names = new String[constants.length]; + for (int i = 0; i < constants.length; i++) { + names[i] = constants[i].name(); } + return names; } } + return null; } - private void writeNodeRef(Node edge) throws IOException { - if (edge != null) { - writeInt(getNodeId(edge)); - } else { - writeInt(-1); + @Override + public String typeName(Object obj) { + if (obj instanceof Class) { + return ((Class) obj).getName(); + } + if (obj instanceof ResolvedJavaType) { + return ((ResolvedJavaType) obj).getName(); } + return null; } - private void writeBlocks(List blocks, BlockMap> blockToNodes) throws IOException { - if (blocks != null && blockToNodes != null) { - for (Block block : blocks) { - List nodes = blockToNodes.get(block); - if (nodes == null) { - writeInt(0); - return; - } - } - writeInt(blocks.size()); - for (Block block : blocks) { - List nodes = blockToNodes.get(block); - List extraNodes = new LinkedList<>(); - writeInt(block.getId()); - for (Node node : nodes) { - if (node instanceof AbstractMergeNode) { - AbstractMergeNode merge = (AbstractMergeNode) node; - for (PhiNode phi : merge.phis()) { - if (!nodes.contains(phi)) { - extraNodes.add(phi); - } - } - } - } - writeInt(nodes.size() + extraNodes.size()); - for (Node node : nodes) { - writeInt(getNodeId(node)); - } - for (Node node : extraNodes) { - writeInt(getNodeId(node)); - } - writeInt(block.getSuccessors().length); - for (Block sux : block.getSuccessors()) { - writeInt(sux.getId()); - } - } - } else { - writeInt(0); + @Override + public byte[] methodCode(ResolvedJavaMethod method) { + return method.getCode(); + } + + @Override + public int methodModifiers(ResolvedJavaMethod method) { + return method.getModifiers(); + } + + @Override + public Signature methodSignature(ResolvedJavaMethod method) { + return method.getSignature(); + } + + @Override + public String methodName(ResolvedJavaMethod method) { + return method.getName(); + } + + @Override + public Object methodDeclaringClass(ResolvedJavaMethod method) { + return method.getDeclaringClass(); + } + + @Override + public int fieldModifiers(ResolvedJavaField field) { + return field.getModifiers(); + } + + @Override + public String fieldTypeName(ResolvedJavaField field) { + return field.getType().getName(); + } + + @Override + public String fieldName(ResolvedJavaField field) { + return field.getName(); + } + + @Override + public Object fieldDeclaringClass(ResolvedJavaField field) { + return field.getDeclaringClass(); + } + + @Override + public ResolvedJavaField field(Object object) { + if (object instanceof ResolvedJavaField) { + return (ResolvedJavaField) object; } + return null; } @Override - public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map properties) throws IOException { - writeByte(BEGIN_GROUP); - writePoolObject(name); - writePoolObject(shortName); - writePoolObject(method); - writeInt(bci); - writeProperties(debug, properties); + public Signature signature(Object object) { + if (object instanceof Signature) { + return (Signature) object; + } + return null; } @Override - public void endGroup() throws IOException { - writeByte(CLOSE_GROUP); + public int signatureParameterCount(Signature signature) { + return signature.getParameterCount(false); } @Override - public void close() { - try { - flush(); - channel.close(); - } catch (IOException ex) { - throw new Error(ex); + public String signatureParameterTypeName(Signature signature, int index) { + return signature.getParameterType(index, null).getName(); + } + + @Override + public String signatureReturnTypeName(Signature signature) { + return signature.getReturnType(null).getName(); + } + + @Override + public NodeSourcePosition nodeSourcePosition(Object object) { + if (object instanceof NodeSourcePosition) { + return (NodeSourcePosition) object; } + return null; + } + + @Override + public ResolvedJavaMethod nodeSourcePositionMethod(NodeSourcePosition pos) { + return pos.getMethod(); + } + + @Override + public NodeSourcePosition nodeSourcePositionCaller(NodeSourcePosition pos) { + return pos.getCaller(); + } + + @Override + public int nodeSourcePositionBCI(NodeSourcePosition pos) { + return pos.getBCI(); } + + @Override + public StackTraceElement methodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { + return method.asStackTraceElement(bci); + } + + static final class GraphInfo { + final DebugContext debug; + final Graph graph; + final ControlFlowGraph cfg; + final BlockMap> blockToNodes; + final NodeMap nodeToBlocks; + final List blocks; + + private GraphInfo(DebugContext debug, Graph graph) { + this.debug = debug; + this.graph = graph; + StructuredGraph.ScheduleResult scheduleResult = null; + if (graph instanceof StructuredGraph) { + + StructuredGraph structuredGraph = (StructuredGraph) graph; + scheduleResult = structuredGraph.getLastSchedule(); + if (scheduleResult == null) { + + // Also provide a schedule when an error occurs + if (DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null) { + try { + SchedulePhase schedule = new SchedulePhase(graph.getOptions()); + schedule.apply(structuredGraph); + scheduleResult = structuredGraph.getLastSchedule(); + } catch (Throwable t) { + } + } + + } + } + cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG(); + blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap(); + nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap(); + blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks()); + } + } + } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java 2017-08-03 22:42:55.517642570 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java 2017-08-03 22:42:55.420638221 -0700 @@ -48,6 +48,7 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugDumpHandler; import org.graalvm.compiler.debug.DebugHandler; @@ -203,7 +204,7 @@ } String ext = PathUtilities.formatExtension(extension); Path result = createUnique(DebugOptions.getDumpDirectory(options), id, label, ext, createDirectory); - if (ShowDumpFiles.getValue(options)) { + if (ShowDumpFiles.getValue(options) || Assertions.assertionsEnabled()) { TTY.println("Dumping debug output to %s", result.toAbsolutePath().toString()); } return result; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java 2017-08-03 22:42:55.860657947 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java 2017-08-03 22:42:55.758653374 -0700 @@ -31,7 +31,7 @@ // empty } - public static final boolean REPLACEMENTS_ASSERTIONS_ENABLED = Assertions.ENABLED; + public static final boolean REPLACEMENTS_ASSERTIONS_ENABLED = Assertions.assertionsEnabled(); /** * Asserts that condition evaluates to true by the time compilation is finished. This is --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java 2017-08-03 22:42:56.192672831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java 2017-08-03 22:42:56.093668393 -0700 @@ -320,6 +320,7 @@ ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp()); if (argumentType == null || (argumentType.isAssignableFrom(targetType.getType()) && !argumentType.equals(targetType.getType()))) { LogicNode inst = InstanceOfNode.createAllowNull(targetType, argument, null, null); + assert !inst.isAlive(); if (!inst.isTautology()) { inst = adder.add(inst); AnchoringNode guardAnchor = adder.getGuardAnchor(); @@ -337,8 +338,6 @@ } ValueNode valueNode = adder.add(PiNode.create(argument, StampFactory.object(targetType), guard.asNode())); arguments[index] = valueNode; - } else { - inst.safeDelete(); } } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java 2017-08-03 22:42:56.524687716 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java 2017-08-03 22:42:56.426683322 -0700 @@ -36,6 +36,8 @@ import org.graalvm.util.Equivalence; import org.graalvm.word.LocationIdentity; +import jdk.vm.ci.meta.JavaKind; + public final class PEReadEliminationBlockState extends PartialEscapeBlockState { final EconomicMap readCache; @@ -45,17 +47,20 @@ public final LocationIdentity identity; public final ValueNode object; public final int index; + public final JavaKind kind; - ReadCacheEntry(LocationIdentity identity, ValueNode object, int index) { + ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind) { this.identity = identity; this.object = object; this.index = index; + this.kind = kind; } @Override public int hashCode() { int result = 31 + ((identity == null) ? 0 : identity.hashCode()); result = 31 * result + ((object == null) ? 0 : System.identityHashCode(object)); + result = 31 * result + kind.ordinal(); return result * 31 + index; } @@ -65,12 +70,12 @@ return false; } ReadCacheEntry other = (ReadCacheEntry) obj; - return identity.equals(other.identity) && object == other.object && index == other.index; + return identity.equals(other.identity) && object == other.object && index == other.index && kind == other.kind; } @Override public String toString() { - return index == -1 ? (object + ":" + identity) : (object + "[" + index + "]:" + identity); + return index == -1 ? (object + ":" + kind + "<" + identity + ">") : (object + "[" + index + "]:" + kind + "<" + identity + ">"); } } @@ -94,7 +99,7 @@ if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < instance.entryCount(); i++) { - readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1), values.get(i)); + readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, instance.field(i).getJavaKind()), values.get(i)); } } } @@ -107,7 +112,7 @@ return super.equivalentTo(other); } - public void addReadCache(ValueNode object, LocationIdentity identity, int index, ValueNode value, PartialEscapeClosure closure) { + public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -116,10 +121,10 @@ } else { cacheObject = object; } - readCache.put(new ReadCacheEntry(identity, cacheObject, index), value); + readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind), value); } - public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, PartialEscapeClosure closure) { + public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -128,7 +133,7 @@ } else { cacheObject = object; } - ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index)); + ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind)); obj = closure.getObjectState(this, cacheValue); if (obj != null) { assert !obj.isVirtual(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java 2017-08-03 22:42:56.851702376 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java 2017-08-03 22:42:56.752697937 -0700 @@ -31,6 +31,7 @@ import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.FieldLocationIdentity; @@ -130,9 +131,9 @@ return false; } - private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) { + private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) { ValueNode unproxiedObject = GraphUtil.unproxify(object); - ValueNode cachedValue = state.getReadCache(object, identity, index, this); + ValueNode cachedValue = state.getReadCache(object, identity, index, kind, this); ValueNode finalValue = getScalarAlias(value); boolean result = false; @@ -141,15 +142,17 @@ result = true; } state.killReadCache(identity, index); - state.addReadCache(unproxiedObject, identity, index, finalValue, this); + state.addReadCache(unproxiedObject, identity, index, kind, finalValue, this); return result; } - private boolean processLoad(FixedNode load, ValueNode object, LocationIdentity identity, int index, PEReadEliminationBlockState state, GraphEffectList effects) { + private boolean processLoad(FixedNode load, ValueNode object, LocationIdentity identity, int index, JavaKind kind, PEReadEliminationBlockState state, GraphEffectList effects) { ValueNode unproxiedObject = GraphUtil.unproxify(object); - ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, this); + ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, kind, this); if (cachedValue != null) { - if (!load.stamp().isCompatible(cachedValue.stamp())) { + Stamp loadStamp = load.stamp(); + Stamp cachedValueStamp = cachedValue.stamp(); + if (!loadStamp.isCompatible(cachedValueStamp)) { /* * Can either be the first field of a two slot write to a one slot field which would * have a non compatible stamp or the second load which will see Illegal. @@ -164,7 +167,7 @@ return true; } } else { - state.addReadCache(unproxiedObject, identity, index, load, this); + state.addReadCache(unproxiedObject, identity, index, kind, load, this); return false; } } @@ -177,13 +180,13 @@ int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE); ValueNode object = GraphUtil.unproxify(load.object()); LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind()); - ValueNode cachedValue = state.getReadCache(object, location, index, this); + ValueNode cachedValue = state.getReadCache(object, location, index, load.accessKind(), this); if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) { effects.replaceAtUsages(load, cachedValue, load); addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(object, location, index, load, this); + state.addReadCache(object, location, index, load.accessKind(), load, this); } } } @@ -197,7 +200,7 @@ if (store.offset().isConstant()) { long offset = store.offset().asJavaConstant().asLong(); int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE); - return processStore(store, store.object(), location, index, store.value(), state, effects); + return processStore(store, store.object(), location, index, store.accessKind(), store.value(), state, effects); } else { processIdentity(state, location); } @@ -208,7 +211,7 @@ } private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) { - return processLoad(length, length.array(), ARRAY_LENGTH_LOCATION, -1, state, effects); + return processLoad(length, length.array(), ARRAY_LENGTH_LOCATION, -1, JavaKind.Int, state, effects); } private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) { @@ -216,7 +219,7 @@ state.killReadCache(); return false; } - return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.value(), state, effects); + return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.field().getJavaKind(), store.value(), state, effects); } private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) { @@ -224,14 +227,14 @@ state.killReadCache(); return false; } - return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, state, effects); + return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, load.field().getJavaKind(), state, effects); } private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) { LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind()); if (store.index().isConstant()) { int index = ((JavaConstant) store.index().asConstant()).asInt(); - return processStore(store, store.array(), arrayLocation, index, store.value(), state, effects); + return processStore(store, store.array(), arrayLocation, index, store.elementKind(), store.value(), state, effects); } else { state.killReadCache(arrayLocation, -1); } @@ -242,13 +245,13 @@ if (load.index().isConstant()) { int index = ((JavaConstant) load.index().asConstant()).asInt(); LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind()); - return processLoad(load, load.array(), arrayLocation, index, state, effects); + return processLoad(load, load.array(), arrayLocation, index, load.elementKind(), state, effects); } return false; } private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) { - return processLoad(unbox, unbox.getValue(), UNBOX_LOCATIONS.get(unbox.getBoxingKind()), -1, state, effects); + return processLoad(unbox, unbox.getValue(), UNBOX_LOCATIONS.get(unbox.getBoxingKind()), -1, unbox.getBoxingKind(), state, effects); } private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) { @@ -290,7 +293,7 @@ if (object != null) { Pair pair = firstValueSet.get(object); while (pair != null) { - initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, initialState.getReadCache().get(entry), this); + initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this); pair = (Pair) pair.getRight(); } } @@ -307,7 +310,7 @@ MapCursor entry = exitState.getReadCache().getEntries(); while (entry.advance()) { if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { - ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, this); + ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, entry.getKey().kind, this); assert value != null : "Got null from read cache, entry's value:" + entry.getValue(); if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) { ProxyNode proxy = new ValueProxyNode(value, exitNode); @@ -366,7 +369,7 @@ PhiNode phiNode = getPhi(key, value.stamp().unrestricted()); mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); for (int i = 0; i < states.size(); i++) { - ValueNode v = states.get(i).getReadCache(key.object, key.identity, key.index, PEReadEliminationClosure.this); + ValueNode v = states.get(i).getReadCache(key.object, key.identity, key.index, key.kind, PEReadEliminationClosure.this); assert phiNode.stamp().isCompatible(v.stamp()) : "Cannot create read elimination phi for inputs with incompatible stamps."; setPhiInput(phiNode, i, v); } @@ -383,19 +386,19 @@ if (phi.getStackKind() == JavaKind.Object) { for (ReadCacheEntry entry : states.get(0).readCache.getKeys()) { if (entry.object == getPhiValueAt(phi, 0)) { - mergeReadCachePhi(phi, entry.identity, entry.index, states); + mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, states); } } } } } - private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, List states) { + private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List states) { ValueNode[] values = new ValueNode[states.size()]; - values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, PEReadEliminationClosure.this); + values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this); if (values[0] != null) { for (int i = 1; i < states.size(); i++) { - ValueNode value = states.get(i).getReadCache(getPhiValueAt(phi, i), identity, index, PEReadEliminationClosure.this); + ValueNode value = states.get(i).getReadCache(getPhiValueAt(phi, i), identity, index, kind, PEReadEliminationClosure.this); // e.g. unsafe loads / stores with same identity and different access kinds see // mergeReadCache(states) if (value == null || !values[i - 1].stamp().isCompatible(value.stamp())) { @@ -404,12 +407,12 @@ values[i] = value; } - PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index), values[0].stamp().unrestricted()); + PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind), values[0].stamp().unrestricted()); mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi"); for (int i = 0; i < values.length; i++) { setPhiInput(phiNode, i, values[i]); } - newState.readCache.put(new ReadCacheEntry(identity, phi, index), phiNode); + newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind), phiNode); } } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java 2017-08-03 22:42:57.187717440 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java 2017-08-03 22:42:57.088713001 -0700 @@ -24,9 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.Map; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; @@ -54,6 +52,19 @@ */ private ObjectState[] objectStates; + public boolean contains(VirtualObjectNode value) { + for (ObjectState state : objectStates) { + if (state != null && state.isVirtual() && state.getEntries() != null) { + for (ValueNode entry : state.getEntries()) { + if (entry == value) { + return true; + } + } + } + } + return false; + } + private static class RefCount { private int refCount = 1; } @@ -310,41 +321,6 @@ return true; } - protected static boolean compareMaps(Map left, Map right) { - if (left.size() != right.size()) { - return false; - } - return compareMapsNoSize(left, right); - } - - protected static boolean compareMapsNoSize(Map left, Map right) { - if (left == right) { - return true; - } - for (Map.Entry entry : right.entrySet()) { - K key = entry.getKey(); - V value = entry.getValue(); - assert value != null; - V otherValue = left.get(key); - if (otherValue != value && !value.equals(otherValue)) { - return false; - } - } - return true; - } - - protected static void meetMaps(Map target, Map source) { - Iterator> iter = target.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - if (source.containsKey(entry.getKey())) { - assert source.get(entry.getKey()) == entry.getValue(); - } else { - iter.remove(); - } - } - } - public void resetObjectStates(int size) { objectStates = new ObjectState[size]; } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java 2017-08-03 22:42:57.518732279 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java 2017-08-03 22:42:57.417727751 -0700 @@ -1009,12 +1009,7 @@ for (int i = 0; i < states.length; i++) { VirtualObjectNode virtual = virtualObjs[i]; - boolean identitySurvives = virtual.hasIdentity() && - // check whether we trivially see that this is the only - // reference to this allocation - !isSingleUsageAllocation(getPhiValueAt(phi, i)); - - if (identitySurvives || !firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) { + if (!firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) { compatible = false; break; } @@ -1024,6 +1019,18 @@ } } if (compatible) { + for (int i = 0; i < states.length; i++) { + VirtualObjectNode virtual = virtualObjs[i]; + /* + * check whether we trivially see that this is the only reference to + * this allocation + */ + if (virtual.hasIdentity() && !isSingleUsageAllocation(getPhiValueAt(phi, i), virtualObjs, states[i])) { + compatible = false; + } + } + } + if (compatible) { VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]); mergeEffects.addFloatingNode(virtual, "valueObjectNode"); mergeEffects.deleteNode(phi); @@ -1069,14 +1076,34 @@ return materialized; } - private boolean isSingleUsageAllocation(ValueNode value) { + private boolean isSingleUsageAllocation(ValueNode value, VirtualObjectNode[] virtualObjs, PartialEscapeBlockState state) { /* * If the phi input is an allocation, we know that it is a "fresh" value, i.e., that * this is a value that will only appear through this source, and cannot appear anywhere * else. If the phi is also the only usage of this input, we know that no other place * can check object identity against it, so it is safe to lose the object identity here. */ - return value instanceof AllocatedObjectNode && value.hasExactlyOneUsage(); + if (!(value instanceof AllocatedObjectNode && value.hasExactlyOneUsage())) { + return false; + } + + /* + * Check that the state only references the one virtual object from the Phi. + */ + VirtualObjectNode singleVirtual = null; + for (int v = 0; v < virtualObjs.length; v++) { + if (state.contains(virtualObjs[v])) { + if (singleVirtual == null) { + singleVirtual = virtualObjs[v]; + } else if (singleVirtual != virtualObjs[v]) { + /* + * More than one virtual object is visible in the object state. + */ + return false; + } + } + } + return true; } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java 2017-08-03 22:42:57.857747478 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java 2017-08-03 22:42:57.758743039 -0700 @@ -151,15 +151,17 @@ public static Builder newBuilder(OptionKey key, String name) { Objects.requireNonNull(key); Objects.requireNonNull(name); - return new Builder(key, name); + return EMPTY.new Builder(key, name); } + private static final OptionDescriptor EMPTY = new OptionDescriptor(null, null, null, null, false); + /** * Represents an option descriptor builder. * * @since 1.0 */ - public static final class Builder { + public final class Builder { private final OptionKey key; private final String name; --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ZeroSignExtendTest.java 2017-08-03 22:42:58.087757789 -0700 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Red Hat Inc. 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; + +/* + * Test compilation of ZeroExtend and SignExtend nodes + */ + +public class ZeroSignExtendTest extends GraalCompilerTest { + + int testSnippet1(char[] chars) { + int x = 1; + x += chars[0]; + x -= chars[1]; + x *= chars[2]; + x /= chars[3]; + x &= chars[4]; + x |= chars[5]; + x ^= chars[6]; + x <<= chars[7]; + x >>= (chars[8] - chars[0]); + x >>>= (chars[9] - chars[0]); + x += chars[1]; + return x; + } + + long testSnippet2(char[] chars) { + long y = 2; + y += chars[0]; + y -= chars[1]; + y *= chars[2]; + y /= chars[3]; + y &= chars[4]; + y |= chars[5]; + y ^= chars[6]; + y <<= chars[7]; + y >>= (chars[8] - chars[0]); + y >>>= (chars[9] - chars[0]); + y += chars[1]; + return y; + } + + int testSnippet3(short[] shorts) { + int x = 1; + x += shorts[0]; + x -= shorts[1]; + x *= shorts[2]; + x /= shorts[3]; + x &= shorts[4]; + x |= shorts[5]; + x ^= shorts[6]; + x <<= shorts[7]; + x >>= (shorts[8] - shorts[0]); + x >>>= (shorts[9] - shorts[0]); + x += shorts[1]; + return x; + } + + long testSnippet4(short[] shorts) { + long y = 2; + y += shorts[0]; + y -= shorts[1]; + y *= shorts[2]; + y /= shorts[3]; + y &= shorts[4]; + y |= shorts[5]; + y ^= shorts[6]; + y <<= shorts[7]; + y >>= (shorts[8] - shorts[0]); + y >>>= (shorts[9] - shorts[0]); + y += shorts[1]; + return y; + } + + int testSnippet5(byte[] bytes) { + int x = 1; + x += bytes[0]; + x -= bytes[1]; + x *= bytes[2]; + x /= bytes[3]; + x &= bytes[4]; + x |= bytes[5]; + x ^= bytes[6]; + x <<= bytes[7]; + x >>= (bytes[8] - bytes[0]); + x >>>= (bytes[9] - bytes[0]); + x += bytes[1]; + return x; + } + + long testSnippet6(byte[] bytes) { + long y = 2; + y += bytes[0]; + y -= bytes[1]; + y *= bytes[2]; + y /= bytes[3]; + y &= bytes[4]; + y |= bytes[5]; + y ^= bytes[6]; + y <<= bytes[7]; + y >>= (bytes[8] - bytes[0]); + y >>>= (bytes[9] - bytes[0]); + y += bytes[1]; + return y; + } + + @Test + + public void test() { + char[] input1 = new char[]{'0', '1', '2', '3', '4', '5', '7', '8', '9', 'A'}; + char[] input2 = new char[]{'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'}; + + short[] input3 = new short[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + short[] input4 = new short[]{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; + + byte[] input5 = new byte[]{21, 22, 23, 24, 25, 26, 27, 28, 29, 30}; + byte[] input6 = new byte[]{11, 12, 13, 14, 15, 16, 17, 18, 19, 40}; + + test("testSnippet1", input1); + test("testSnippet2", input2); + test("testSnippet3", input3); + test("testSnippet4", input4); + test("testSnippet5", input5); + test("testSnippet6", input6); + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/CountUppercaseParallelTest.java 2017-08-03 22:42:58.394771553 -0700 @@ -0,0 +1,42 @@ +/* + * 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.core.test.ea; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Test; + +public class CountUppercaseParallelTest extends GraalCompilerTest { + public static long count(CharSequence sentence) { + return sentence.chars().parallel().filter(c -> Character.isUpperCase(c)).count(); + } + + @Test + public void testCount() { + String sequence = "In 2017 I would like to run ALL languages in one VM."; + for (int i = 0; i < 5000; i++) { + count(sequence); + } + test("count", sequence); + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTreesTest.java 2017-08-03 22:42:58.700785272 -0700 @@ -0,0 +1,136 @@ +/* + * 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.core.test.ea; + +import java.util.HashSet; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.nodes.debug.BlackholeNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/* + * Test whether complex tree structures properly maintain identity. + */ +public class PartialEscapeAnalysisTreesTest extends EATestBase { + + static class TreeNode { + TreeNode left; + TreeNode right; + + TreeNode() { + + } + + TreeNode(TreeNode left, TreeNode right) { + this.left = left; + this.right = right; + } + + public void visit(HashSet instances) { + instances.add(this); + if (left != null) { + left.visit(instances); + } + if (right != null) { + right.visit(instances); + } + } + + int countInstances() { + HashSet instances = new HashSet<>(); + visit(instances); + return instances.size(); + } + } + + public static TreeNode buildTree(boolean a) { + TreeNode leftChild; + TreeNode rightChild; + TreeNode taskToFork; + TreeNode task; + if (a) { + GraalDirectives.blackhole(new TreeNode()); + leftChild = new TreeNode(); + rightChild = new TreeNode(); + task = new TreeNode(leftChild, rightChild); + taskToFork = rightChild; + GraalDirectives.blackhole(task); + } else { + leftChild = new TreeNode(); + rightChild = new TreeNode(); + task = new TreeNode(leftChild, rightChild); + taskToFork = leftChild; + GraalDirectives.blackhole(task); + } + if (taskToFork.left == null) { + taskToFork.left = new TreeNode(); + } + + return new TreeNode(task, null); + } + + @Test + public void testBuildTree() { + testGraph("buildTree"); + } + + /** + * Prepare a graph that includes some blackholes and then remove the blackholes and compile + * normally to create an unusual situation for PEA. + */ + @SuppressWarnings("try") + public void testGraph(String name) { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + + prepareGraph(name, true); + try (DebugContext.Scope s = graph.getDebug().scope(getClass(), method, getCodeCache(), graph)) { + for (BlackholeNode node : graph.getNodes().filter(BlackholeNode.class)) { + graph.removeFixed(node); + } + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + + InstalledCode code = getCode(method, graph, true); + + GraalCompilerTest.Result r = executeExpected(method, null, true); + int expectedInstances = ((TreeNode) r.returnValue).countInstances(); + TreeNode r2 = (TreeNode) code.executeVarargs(true); + Assert.assertEquals("Wrong number of nodes in tree", expectedInstances, r2.countInstances()); + + r = executeExpected(method, null, false); + expectedInstances = ((TreeNode) r.returnValue).countInstances(); + r2 = (TreeNode) code.executeVarargs(false); + Assert.assertEquals("Wrong number of nodes in tree", expectedInstances, r2.countInstances()); + } catch (Throwable e) { + throw graph.getDebug().handle(e); + } + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/StateSplitProxyNode.java 2017-08-03 22:42:59.018799528 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, 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.nodes.extended; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +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.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.ValueNode; + +/** + * This node provides a state split along with the functionality of {@link FixedValueAnchorNode}. + */ +@NodeInfo(cycles = CYCLES_0, size = SIZE_0) +public final class StateSplitProxyNode extends FixedValueAnchorNode implements Canonicalizable, StateSplit { + + public static final NodeClass TYPE = NodeClass.create(StateSplitProxyNode.class); + + @OptionalInput(InputType.State) FrameState stateAfter; + + @Override + public FrameState stateAfter() { + return stateAfter; + } + + @Override + public void setStateAfter(FrameState x) { + assert x == null || x.isAlive() : "frame state must be in a graph"; + updateUsages(stateAfter, x); + stateAfter = x; + } + + @Override + public boolean hasSideEffect() { + return true; + } + + public StateSplitProxyNode(ValueNode object) { + super(TYPE, object); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (object.isConstant()) { + return object; + } + return this; + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadNode.java 2017-08-03 22:42:59.331813561 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Red Hat Inc. 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.aarch64; + +import jdk.vm.ci.aarch64.AArch64Kind; +import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; +import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.word.LocationIdentity; + +/** + * AArch64-specific subclass of ReadNode that knows how to merge ZeroExtend and SignExtend into the + * read. + */ + +@NodeInfo +public class AArch64ReadNode extends ReadNode { + public static final NodeClass TYPE = NodeClass.create(AArch64ReadNode.class); + private final IntegerStamp accessStamp; + private final boolean isSigned; + + public AArch64ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, + FrameState stateBefore, IntegerStamp accessStamp, boolean isSigned) { + super(TYPE, address, location, stamp, guard, barrierType, nullCheck, stateBefore); + this.accessStamp = accessStamp; + this.isSigned = isSigned; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + AArch64LIRGenerator lirgen = (AArch64LIRGenerator) gen.getLIRGeneratorTool(); + AArch64ArithmeticLIRGenerator arithgen = (AArch64ArithmeticLIRGenerator) lirgen.getArithmetic(); + AArch64Kind readKind = (AArch64Kind) lirgen.getLIRKind(accessStamp).getPlatformKind(); + int resultBits = ((IntegerStamp) stamp()).getBits(); + gen.setResult(this, arithgen.emitExtendMemory(isSigned, readKind, resultBits, (AArch64AddressValue) gen.operand(getAddress()), gen.state(this))); + } + + /** + * replace a ReadNode with an AArch64-specific variant which knows how to merge a downstream + * zero or sign extend into the read operation. + * + * @param readNode + */ + public static void replace(ReadNode readNode) { + assert readNode.getUsageCount() == 1; + assert readNode.getUsageAt(0) instanceof ZeroExtendNode || readNode.getUsageAt(0) instanceof SignExtendNode; + + ValueNode usage = (ValueNode) readNode.getUsageAt(0); + boolean isSigned = usage instanceof SignExtendNode; + IntegerStamp accessStamp = ((IntegerStamp) readNode.getAccessStamp()); + + AddressNode address = readNode.getAddress(); + LocationIdentity location = readNode.getLocationIdentity(); + Stamp stamp = usage.stamp(); + GuardingNode guard = readNode.getGuard(); + BarrierType barrierType = readNode.getBarrierType(); + boolean nullCheck = readNode.getNullCheck(); + FrameState stateBefore = readNode.stateBefore(); + AArch64ReadNode clone = new AArch64ReadNode(address, location, stamp, guard, barrierType, nullCheck, stateBefore, accessStamp, isSigned); + StructuredGraph graph = readNode.graph(); + graph.add(clone); + // splice out the extend node + usage.replaceAtUsagesAndDelete(readNode); + // swap the clone for the read + graph.replaceFixedWithFixed(readNode, clone); + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadReplacementPhase.java 2017-08-03 22:42:59.639827370 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Red Hat Inc. 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.aarch64; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.phases.Phase; + +/** + * AArch64-specific phase which substitutes certain read nodes with arch-specific variants in order + * to allow merging of zero and sign extension into the read operation. + */ + +public class AArch64ReadReplacementPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + for (Node node : graph.getNodes()) { + // don't process nodes we just added + if (node instanceof AArch64ReadNode) { + continue; + } + if (node instanceof ReadNode) { + ReadNode readNode = (ReadNode) node; + if (readNode.getUsageCount() == 1) { + Node usage = readNode.getUsageAt(0); + if (usage instanceof ZeroExtendNode || usage instanceof SignExtendNode) { + AArch64ReadNode.replace(readNode); + } + } + } + } + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnVolatileReadTest.java 2017-08-03 22:42:59.956841582 -0700 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011, 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.test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Test; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests that deoptimization upon volatile read will not roll back the read. The test cases rely on + * the fact that invocations to {@link GraalDirectives} utilities are substituted and not valid + * targets for deoptimization. + */ +public class DeoptimizeOnVolatileReadTest extends GraalCompilerTest { + + static class Dummy { + boolean f1 = false; + volatile boolean f2 = false; + } + + public static int test1Snippet(Dummy dummy) { + if (GraalDirectives.injectBranchProbability(0, GraalDirectives.inCompiledCode() & dummy.f1)) { + return 1; + } + + return 0; + } + + @Test + public void test1() { + ResolvedJavaMethod method = getResolvedJavaMethod("test1Snippet"); + + Dummy dummy = new Dummy(); + Result expected = executeExpected(method, null, dummy); + assertEquals(new Result(0, null), expected); + + dummy.f1 = true; + + InstalledCode code = getCode(method); + Result actual; + + try { + actual = new Result(code.executeVarargs(dummy), null); + } catch (Exception e) { + actual = new Result(null, e); + } + + // The code should get deoptimized, and resume execution at the beginning of the method. + // Therefore it does not re-enter the branch as inCompiledCode() is false. + assertEquals(new Result(0, null), actual); + assertFalse(code.isValid()); + } + + public static int test2Snippet(Dummy dummy) { + if (GraalDirectives.injectBranchProbability(0, GraalDirectives.inCompiledCode() & dummy.f2)) { + return 1; + } + + return 0; + } + + @Test + public void test2() { + ResolvedJavaMethod method = getResolvedJavaMethod("test2Snippet"); + + Dummy dummy = new Dummy(); + Result expected = executeExpected(method, null, dummy); + assertEquals(new Result(0, null), expected); + + dummy.f2 = true; + + InstalledCode code = getCode(method); + Result actual; + + try { + actual = new Result(code.executeVarargs(dummy), null); + } catch (Exception e) { + actual = new Result(null, e); + } + + // The code should get deoptimized, and resume execution at the then-branch. + assertEquals(new Result(1, null), actual); + assertFalse(code.isValid()); + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/DefaultGraphBlocks.java 2017-08-03 22:43:00.275855884 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, 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.graphio; + +import java.util.Collection; +import java.util.Collections; + +final class DefaultGraphBlocks implements GraphBlocks { + private static final DefaultGraphBlocks DEFAULT = new DefaultGraphBlocks(); + + private DefaultGraphBlocks() { + } + + @SuppressWarnings("unchecked") + public static GraphBlocks empty() { + return (GraphBlocks) DEFAULT; + } + + @Override + public Collection blocks(Object graph) { + return Collections.emptyList(); + } + + @Override + public int blockId(Object block) { + return -1; + } + + @Override + public Collection blockNodes(Object info, Object block) { + return Collections.emptyList(); + } + + @Override + public Collection blockSuccessors(Object block) { + return Collections.emptyList(); + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/DefaultGraphTypes.java 2017-08-03 22:43:00.585869782 -0700 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011, 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.graphio; + +final class DefaultGraphTypes implements GraphTypes { + static final GraphTypes DEFAULT = new DefaultGraphTypes(); + + private DefaultGraphTypes() { + } + + @Override + public Class enumClass(Object enumValue) { + if (enumValue instanceof Enum) { + return enumValue.getClass(); + } + return null; + } + + @Override + public int enumOrdinal(Object obj) { + if (obj instanceof Enum) { + return ((Enum) obj).ordinal(); + } + return -1; + } + + @SuppressWarnings("unchecked") + @Override + public String[] enumTypeValues(Object clazz) { + if (clazz instanceof Class) { + Class> enumClass = (Class>) clazz; + Enum[] constants = enumClass.getEnumConstants(); + if (constants != null) { + String[] names = new String[constants.length]; + for (int i = 0; i < constants.length; i++) { + names[i] = constants[i].name(); + } + return names; + } + } + return null; + } + + @Override + public String typeName(Object clazz) { + if (clazz instanceof Class) { + return ((Class) clazz).getName(); + } + return null; + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphBlocks.java 2017-08-03 22:43:00.901883949 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, 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.graphio; + +import java.util.Collection; + +/** + * Special support for dealing with blocks. + * + * @param the type that represents the graph + * @param the type that represents the block + * @param the type of the node + */ +public interface GraphBlocks { + /** + * All blocks in the graph. + * + * @param graph the graph + * @return collection of blocks in the graph + */ + Collection blocks(G graph); + + /** + * Unique id of a block. + * + * @param block the block + * @return the id of the block + */ + int blockId(B block); + + Collection blockNodes(G info, B block); + + Collection blockSuccessors(B block); +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphElements.java 2017-08-03 22:43:01.211897847 -0700 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2011, 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.graphio; + +/** + * Representation of methods, fields, their signatures and code locations. + * + * @param type representing methods + * @param type representing fields + * @param type representing signature + * @param

type representing source code location + */ +public interface GraphElements { + /** + * Recognize method. Can the object be seen as a method? + * + * @param obj the object to check + * @return null if the object isn't a method, non-null value otherwise + */ + M method(Object obj); + + /** + * Bytecode for a method. + * + * @param method the method + * @return bytecode of the method + */ + byte[] methodCode(M method); + + /** + * Method modifiers. + * + * @param method the method + * @return its modifiers + */ + int methodModifiers(M method); + + /** + * Method's signature. + * + * @param method the method + * @return signature of the method + */ + S methodSignature(M method); + + /** + * Method name. + * + * @param method the method + * @return name of the method + */ + String methodName(M method); + + /** + * Method's declaring class. The returned object shall be a {@link Class} or be recognizable by + * {@link GraphTypes#typeName(java.lang.Object)} method. + * + * @param method the method + * @return object representing class that defined the method + */ + Object methodDeclaringClass(M method); + + /** + * Recognizes a field. Can the object be seen as a field? + * + * @param object the object to check + * @return null if the object isn't a field, non-null value otherwise + */ + F field(Object object); + + /** + * Field modifiers. + * + * @param field the field + * @return field modifiers + */ + int fieldModifiers(F field); + + /** + * Type name of the field. + * + * @param field the field + * @return the name of the field's type + */ + String fieldTypeName(F field); + + /** + * Name of a field. + * + * @param field the field + * @return the name of the field + */ + String fieldName(F field); + + /** + * Field's declaring class. The returned object shall be a {@link Class} or be recognizable by + * {@link GraphTypes#typeName(java.lang.Object)} method. + * + * @param field the field + * @return object representing class that defined the field + */ + Object fieldDeclaringClass(F field); + + /** + * Recognizes signature. Can the object be seen as a signature? + * + * @param object the object to check + * @return null if the object isn't a signature, non-null value otherwise + */ + S signature(Object object); + + /** + * Number of parameters of a signature. + * + * @param signature the signature + * @return number of parameters + */ + int signatureParameterCount(S signature); + + /** + * Type name of a signature parameter. + * + * @param signature the signature + * @param index index from 0 to {@link #signatureParameterCount(java.lang.Object)} - 1 + * @return the type name + */ + String signatureParameterTypeName(S signature, int index); + + /** + * Type name of a return type. + * + * @param signature the signature + * @return the type name + */ + String signatureReturnTypeName(S signature); + + /** + * Recognize a source position. Can the object be seen as a position? + * + * @param object the object to check + * @return null if the object isn't a position, non-null otherwise + */ + P nodeSourcePosition(Object object); + + /** + * Method for a position. + * + * @param pos the position + * @return the method at the position + */ + M nodeSourcePositionMethod(P pos); + + /** + * Caller of a position. + * + * @param pos the position + * @return null or another position + */ + P nodeSourcePositionCaller(P pos); + + /** + * Byte code index of a position. + * + * @param pos the position + * @return the BCI of the position + */ + int nodeSourcePositionBCI(P pos); + + /** + * Stack trace element for a method, index and position. + * + * @param method the method + * @param bci the index + * @param pos the position + * @return stack trace element for the method, index and position + */ + StackTraceElement methodStackTraceElement(M method, int bci, P pos); +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java 2017-08-03 22:43:01.521911745 -0700 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011, 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.graphio; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.channels.WritableByteChannel; +import java.util.Map; + +/** + * Instance of output to dump informations about a compiler compilations. + * + * @param the type of graph this instance handles + * @param the type of methods this instance handles + */ +public final class GraphOutput implements Closeable { + private final GraphProtocol printer; + + private GraphOutput(GraphProtocol p) { + this.printer = p; + } + + /** + * Creates new builder to configure a future instance of {@link GraphOutput}. + * + * @param the type of the graph + * @param the type of the nodes + * @param the type of the node classes + * @param

the type of the ports + * + * @param structure description of the structure of the graph + * @return the builder to configure + */ + public static Builder newBuilder(GraphStructure structure) { + return new Builder<>(structure); + } + + /** + * Begins a compilation group. + * + * @param forGraph + * @param name + * @param shortName + * @param method + * @param bci + * @param properties + * @throws IOException + */ + public void beginGroup(G forGraph, String name, String shortName, M method, int bci, Map properties) throws IOException { + printer.beginGroup(forGraph, name, shortName, method, bci, properties); + } + + /** + * Prints a single graph. + * + * @param graph + * @param properties + * @param id + * @param format + * @param args + * @throws IOException + */ + public void print(G graph, Map properties, int id, String format, Object... args) throws IOException { + printer.print(graph, properties, id, format, args); + } + + /** + * Ends compilation group. + * + * @throws IOException + */ + public void endGroup() throws IOException { + printer.endGroup(); + } + + /** + * Closes the output. Closes allocated resources and associated output channel. + */ + @Override + public void close() { + printer.close(); + } + + /** + * Builder to configure and create an instance of {@link GraphOutput}. + * + * @param the type of the (root element of) graph + * @param the type of the nodes + * @param the type of the methods + */ + public static final class Builder { + private final GraphStructure structure; + private GraphElements elements = null; + private GraphTypes types = DefaultGraphTypes.DEFAULT; + private GraphBlocks blocks = DefaultGraphBlocks.empty(); + + Builder(GraphStructure structure) { + this.structure = structure; + } + + /** + * Associates different implementation of types. + * + * @param graphTypes implementation of types and enum recognition + * @return this builder + */ + public Builder types(GraphTypes graphTypes) { + this.types = graphTypes; + return this; + } + + /** + * Associates implementation of blocks. + * + * @param graphBlocks the blocks implementation + * @return this builder + */ + public Builder blocks(GraphBlocks graphBlocks) { + this.blocks = graphBlocks; + return this; + } + + /** + * Associates implementation of graph elements. + * + * @param graphElements the elements implementation + * @return this builder + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public Builder elements(GraphElements graphElements) { + this.elements = (GraphElements) graphElements; + return (Builder) this; + } + + /** + * Creates new {@link GraphOutput} to output to provided channel. The output will use + * interfaces currently associated with this builder. + * + * @param channel the channel to output to + * @return new graph output + * @throws IOException if something goes wrong when writing to the channel + */ + public GraphOutput build(WritableByteChannel channel) throws IOException { + ProtocolImpl p = new ProtocolImpl<>(structure, types, blocks, elements, channel); + return new GraphOutput<>(p); + } + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java 2017-08-03 22:43:01.829925554 -0700 @@ -0,0 +1,678 @@ +/* + * Copyright (c) 2011, 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.graphio; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; + +abstract class GraphProtocol implements Closeable { + private static final Charset UTF8 = Charset.forName("UTF-8"); + + private static final int CONSTANT_POOL_MAX_SIZE = 8000; + + private static final int BEGIN_GROUP = 0x00; + private static final int BEGIN_GRAPH = 0x01; + private static final int CLOSE_GROUP = 0x02; + + private static final int POOL_NEW = 0x00; + private static final int POOL_STRING = 0x01; + private static final int POOL_ENUM = 0x02; + private static final int POOL_CLASS = 0x03; + private static final int POOL_METHOD = 0x04; + private static final int POOL_NULL = 0x05; + private static final int POOL_NODE_CLASS = 0x06; + private static final int POOL_FIELD = 0x07; + private static final int POOL_SIGNATURE = 0x08; + private static final int POOL_NODE_SOURCE_POSITION = 0x09; + + private static final int PROPERTY_POOL = 0x00; + private static final int PROPERTY_INT = 0x01; + private static final int PROPERTY_LONG = 0x02; + private static final int PROPERTY_DOUBLE = 0x03; + private static final int PROPERTY_FLOAT = 0x04; + private static final int PROPERTY_TRUE = 0x05; + private static final int PROPERTY_FALSE = 0x06; + private static final int PROPERTY_ARRAY = 0x07; + private static final int PROPERTY_SUBGRAPH = 0x08; + + private static final int KLASS = 0x00; + private static final int ENUM_KLASS = 0x01; + + private static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'}; + + private final ConstantPool constantPool; + private final ByteBuffer buffer; + private final WritableByteChannel channel; + private final int versionMajor; + private final int versionMinor; + + protected GraphProtocol(WritableByteChannel channel) throws IOException { + this(channel, 4, 0); + } + + private GraphProtocol(WritableByteChannel channel, int major, int minor) throws IOException { + if (major > 4) { + throw new IllegalArgumentException(); + } + if (major == 4 && minor > 0) { + throw new IllegalArgumentException(); + } + this.versionMajor = major; + this.versionMinor = minor; + this.constantPool = new ConstantPool(); + this.buffer = ByteBuffer.allocateDirect(256 * 1024); + this.channel = channel; + writeVersion(); + } + + @SuppressWarnings("all") + public final void print(Graph graph, Map properties, int id, String format, Object... args) throws IOException { + writeByte(BEGIN_GRAPH); + if (versionMajor >= 3) { + writeInt(id); + writeString(format); + writeInt(args.length); + for (Object a : args) { + writePropertyObject(graph, a); + } + } else { + writePoolObject(formatTitle(graph, id, format, args)); + } + writeGraph(graph, properties); + flush(); + } + + public final void beginGroup(Graph noGraph, String name, String shortName, ResolvedJavaMethod method, int bci, Map properties) throws IOException { + writeByte(BEGIN_GROUP); + writePoolObject(name); + writePoolObject(shortName); + writePoolObject(method); + writeInt(bci); + writeProperties(noGraph, properties); + } + + public final void endGroup() throws IOException { + writeByte(CLOSE_GROUP); + } + + @Override + public final void close() { + try { + flush(); + channel.close(); + } catch (IOException ex) { + throw new Error(ex); + } + } + + protected abstract Graph findGraph(Graph current, Object obj); + + protected abstract ResolvedJavaMethod findMethod(Object obj); + + protected abstract NodeClass findNodeClass(Object obj); + + /** + * Find a Java class. The returned object must be acceptable by + * {@link #findJavaTypeName(java.lang.Object)} and return valid name for the class. + * + * @param clazz node class object + * @return object representing the class, for example {@link Class} + */ + protected abstract Object findJavaClass(NodeClass clazz); + + protected abstract Object findEnumClass(Object enumValue); + + protected abstract String findNameTemplate(NodeClass clazz); + + protected abstract Edges findClassEdges(NodeClass nodeClass, boolean dumpInputs); + + protected abstract int findNodeId(Node n); + + protected abstract void findExtraNodes(Node node, Collection extraNodes); + + protected abstract boolean hasPredecessor(Node node); + + protected abstract int findNodesCount(Graph info); + + protected abstract Iterable findNodes(Graph info); + + protected abstract void findNodeProperties(Node node, Map props, Graph info); + + protected abstract Collection findBlockNodes(Graph info, Block block); + + protected abstract int findBlockId(Block sux); + + protected abstract Collection findBlocks(Graph graph); + + protected abstract Collection findBlockSuccessors(Block block); + + protected abstract String formatTitle(Graph graph, int id, String format, Object... args); + + protected abstract int findSize(Edges edges); + + protected abstract boolean isDirect(Edges edges, int i); + + protected abstract String findName(Edges edges, int i); + + protected abstract Object findType(Edges edges, int i); + + protected abstract Collection findNodes(Graph graph, Node node, Edges edges, int i); + + protected abstract int findEnumOrdinal(Object obj); + + protected abstract String[] findEnumTypeValues(Object clazz); + + protected abstract String findJavaTypeName(Object obj); + + protected abstract byte[] findMethodCode(ResolvedJavaMethod method); + + protected abstract int findMethodModifiers(ResolvedJavaMethod method); + + protected abstract Signature findMethodSignature(ResolvedJavaMethod method); + + protected abstract String findMethodName(ResolvedJavaMethod method); + + protected abstract Object findMethodDeclaringClass(ResolvedJavaMethod method); + + protected abstract int findFieldModifiers(ResolvedJavaField field); + + protected abstract String findFieldTypeName(ResolvedJavaField field); + + protected abstract String findFieldName(ResolvedJavaField field); + + protected abstract Object findFieldDeclaringClass(ResolvedJavaField field); + + protected abstract ResolvedJavaField findJavaField(Object object); + + protected abstract Signature findSignature(Object object); + + protected abstract int findSignatureParameterCount(Signature signature); + + protected abstract String findSignatureParameterTypeName(Signature signature, int index); + + protected abstract String findSignatureReturnTypeName(Signature signature); + + protected abstract NodeSourcePosition findNodeSourcePosition(Object object); + + protected abstract ResolvedJavaMethod findNodeSourcePositionMethod(NodeSourcePosition pos); + + protected abstract NodeSourcePosition findNodeSourcePositionCaller(NodeSourcePosition pos); + + protected abstract int findNodeSourcePositionBCI(NodeSourcePosition pos); + + protected abstract StackTraceElement findMethodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos); + + private void writeVersion() throws IOException { + writeBytesRaw(MAGIC_BYTES); + writeByte(versionMajor); + writeByte(versionMinor); + } + + private void flush() throws IOException { + buffer.flip(); + /* + * Try not to let interrupted threads aborting the write. There's still a race here but an + * interrupt that's been pending for a long time shouldn't stop this writing. + */ + boolean interrupted = Thread.interrupted(); + try { + channel.write(buffer); + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + buffer.compact(); + } + + private void ensureAvailable(int i) throws IOException { + assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small"; + while (buffer.remaining() < i) { + flush(); + } + } + + private void writeByte(int b) throws IOException { + ensureAvailable(1); + buffer.put((byte) b); + } + + private void writeInt(int b) throws IOException { + ensureAvailable(4); + buffer.putInt(b); + } + + private void writeLong(long b) throws IOException { + ensureAvailable(8); + buffer.putLong(b); + } + + private void writeDouble(double b) throws IOException { + ensureAvailable(8); + buffer.putDouble(b); + } + + private void writeFloat(float b) throws IOException { + ensureAvailable(4); + buffer.putFloat(b); + } + + private void writeShort(char b) throws IOException { + ensureAvailable(2); + buffer.putChar(b); + } + + private void writeString(String str) throws IOException { + byte[] bytes = str.getBytes(UTF8); + writeBytes(bytes); + } + + private void writeBytes(byte[] b) throws IOException { + if (b == null) { + writeInt(-1); + } else { + writeInt(b.length); + writeBytesRaw(b); + } + } + + private void writeBytesRaw(byte[] b) throws IOException { + int bytesWritten = 0; + while (bytesWritten < b.length) { + int toWrite = Math.min(b.length - bytesWritten, buffer.capacity()); + ensureAvailable(toWrite); + buffer.put(b, bytesWritten, toWrite); + bytesWritten += toWrite; + } + } + + private void writeInts(int[] b) throws IOException { + if (b == null) { + writeInt(-1); + } else { + writeInt(b.length); + int sizeInBytes = b.length * 4; + ensureAvailable(sizeInBytes); + buffer.asIntBuffer().put(b); + buffer.position(buffer.position() + sizeInBytes); + } + } + + private void writeDoubles(double[] b) throws IOException { + if (b == null) { + writeInt(-1); + } else { + writeInt(b.length); + int sizeInBytes = b.length * 8; + ensureAvailable(sizeInBytes); + buffer.asDoubleBuffer().put(b); + buffer.position(buffer.position() + sizeInBytes); + } + } + + private void writePoolObject(Object object) throws IOException { + if (object == null) { + writeByte(POOL_NULL); + return; + } + Character id = constantPool.get(object); + if (id == null) { + addPoolEntry(object); + } else { + if (object instanceof Enum || findEnumOrdinal(object) >= 0) { + writeByte(POOL_ENUM); + } else if (object instanceof Class || findJavaTypeName(object) != null) { + writeByte(POOL_CLASS); + } else if (findJavaField(object) != null) { + writeByte(POOL_FIELD); + } else if (findSignature(object) != null) { + writeByte(POOL_SIGNATURE); + } else if (versionMajor >= 4 && findNodeSourcePosition(object) != null) { + writeByte(POOL_NODE_SOURCE_POSITION); + } else { + if (findNodeClass(object) != null) { + writeByte(POOL_NODE_CLASS); + } else if (findMethod(object) != null) { + writeByte(POOL_METHOD); + } else { + writeByte(POOL_STRING); + } + } + writeShort(id.charValue()); + } + } + + private void writeGraph(Graph graph, Map properties) throws IOException { + writeProperties(graph, properties); + writeNodes(graph); + writeBlocks(findBlocks(graph), graph); + } + + private void writeNodes(Graph info) throws IOException { + Map props = new HashMap<>(); + + final int size = findNodesCount(info); + writeInt(size); + int cnt = 0; + for (Node node : findNodes(info)) { + NodeClass nodeClass = findNodeClass(node); + if (nodeClass == null) { + throw new IOException("No class for " + node); + } + findNodeProperties(node, props, info); + + writeInt(findNodeId(node)); + writePoolObject(nodeClass); + writeByte(hasPredecessor(node) ? 1 : 0); + writeProperties(info, props); + writeEdges(info, node, true); + writeEdges(info, node, false); + + props.clear(); + cnt++; + } + if (size != cnt) { + throw new IOException("Expecting " + size + " nodes, but found " + cnt); + } + } + + private void writeEdges(Graph graph, Node node, boolean dumpInputs) throws IOException { + NodeClass clazz = findNodeClass(node); + Edges edges = findClassEdges(clazz, dumpInputs); + int size = findSize(edges); + for (int i = 0; i < size; i++) { + Collection list = findNodes(graph, node, edges, i); + if (isDirect(edges, i)) { + if (list != null && list.size() != 1) { + throw new IOException("Edge " + i + " in " + edges + " is direct, but list isn't singleton: " + list); + } + Node n = null; + if (list != null && !list.isEmpty()) { + n = list.iterator().next(); + } + writeNodeRef(n); + } else { + if (list == null) { + writeShort((char) 0); + } else { + int listSize = list.size(); + assert listSize == ((char) listSize); + writeShort((char) listSize); + for (Node edge : list) { + writeNodeRef(edge); + } + } + } + } + } + + private void writeNodeRef(Node node) throws IOException { + writeInt(findNodeId(node)); + } + + private void writeBlocks(Collection blocks, Graph info) throws IOException { + if (blocks != null) { + for (Block block : blocks) { + Collection nodes = findBlockNodes(info, block); + if (nodes == null) { + writeInt(0); + return; + } + } + writeInt(blocks.size()); + for (Block block : blocks) { + Collection nodes = findBlockNodes(info, block); + writeInt(findBlockId(block)); + writeInt(nodes.size()); + for (Node node : nodes) { + writeInt(findNodeId(node)); + } + final Collection successors = findBlockSuccessors(block); + writeInt(successors.size()); + for (Block sux : successors) { + writeInt(findBlockId(sux)); + } + } + } else { + writeInt(0); + } + } + + private void writeEdgesInfo(NodeClass nodeClass, boolean dumpInputs) throws IOException { + Edges edges = findClassEdges(nodeClass, dumpInputs); + int size = findSize(edges); + writeShort((char) size); + for (int i = 0; i < size; i++) { + writeByte(isDirect(edges, i) ? 0 : 1); + writePoolObject(findName(edges, i)); + if (dumpInputs) { + writePoolObject(findType(edges, i)); + } + } + } + + @SuppressWarnings("all") + private void addPoolEntry(Object object) throws IOException { + ResolvedJavaField field; + String typeName; + Signature signature; + NodeSourcePosition pos; + int enumOrdinal; + char index = constantPool.add(object); + writeByte(POOL_NEW); + writeShort(index); + if ((typeName = findJavaTypeName(object)) != null) { + writeByte(POOL_CLASS); + writeString(typeName); + String[] enumValueNames = findEnumTypeValues(object); + if (enumValueNames != null) { + writeByte(ENUM_KLASS); + writeInt(enumValueNames.length); + for (String o : enumValueNames) { + writePoolObject(o); + } + } else { + writeByte(KLASS); + } + } else if ((enumOrdinal = findEnumOrdinal(object)) >= 0) { + writeByte(POOL_ENUM); + writePoolObject(findEnumClass(object)); + writeInt(enumOrdinal); + } else if ((field = findJavaField(object)) != null) { + writeByte(POOL_FIELD); + writePoolObject(findFieldDeclaringClass(field)); + writePoolObject(findFieldName(field)); + writePoolObject(findFieldTypeName(field)); + writeInt(findFieldModifiers(field)); + } else if ((signature = findSignature(object)) != null) { + writeByte(POOL_SIGNATURE); + int args = findSignatureParameterCount(signature); + writeShort((char) args); + for (int i = 0; i < args; i++) { + writePoolObject(findSignatureParameterTypeName(signature, i)); + } + writePoolObject(findSignatureReturnTypeName(signature)); + } else if (versionMajor >= 4 && (pos = findNodeSourcePosition(object)) != null) { + writeByte(POOL_NODE_SOURCE_POSITION); + ResolvedJavaMethod method = findNodeSourcePositionMethod(pos); + writePoolObject(method); + final int bci = findNodeSourcePositionBCI(pos); + writeInt(bci); + StackTraceElement ste = findMethodStackTraceElement(method, bci, pos); + if (ste != null) { + writePoolObject(ste.getFileName()); + writeInt(ste.getLineNumber()); + } else { + writePoolObject(null); + } + writePoolObject(findNodeSourcePositionCaller(pos)); + } else { + NodeClass nodeClass = findNodeClass(object); + if (nodeClass != null) { + writeByte(POOL_NODE_CLASS); + final Object clazz = findJavaClass(nodeClass); + if (versionMajor >= 3) { + writePoolObject(clazz); + writeString(findNameTemplate(nodeClass)); + } else { + writeString(((Class) clazz).getSimpleName()); + String nameTemplate = findNameTemplate(nodeClass); + writeString(nameTemplate); + } + writeEdgesInfo(nodeClass, true); + writeEdgesInfo(nodeClass, false); + return; + } + ResolvedJavaMethod method = findMethod(object); + if (method == null) { + writeByte(POOL_STRING); + writeString(object.toString()); + return; + } + writeByte(POOL_METHOD); + writePoolObject(findMethodDeclaringClass(method)); + writePoolObject(findMethodName(method)); + writePoolObject(findMethodSignature(method)); + writeInt(findMethodModifiers(method)); + writeBytes(findMethodCode(method)); + } + } + + private void writePropertyObject(Graph graph, Object obj) throws IOException { + if (obj instanceof Integer) { + writeByte(PROPERTY_INT); + writeInt(((Integer) obj).intValue()); + } else if (obj instanceof Long) { + writeByte(PROPERTY_LONG); + writeLong(((Long) obj).longValue()); + } else if (obj instanceof Double) { + writeByte(PROPERTY_DOUBLE); + writeDouble(((Double) obj).doubleValue()); + } else if (obj instanceof Float) { + writeByte(PROPERTY_FLOAT); + writeFloat(((Float) obj).floatValue()); + } else if (obj instanceof Boolean) { + if (((Boolean) obj).booleanValue()) { + writeByte(PROPERTY_TRUE); + } else { + writeByte(PROPERTY_FALSE); + } + } else if (obj != null && obj.getClass().isArray()) { + Class componentType = obj.getClass().getComponentType(); + if (componentType.isPrimitive()) { + if (componentType == Double.TYPE) { + writeByte(PROPERTY_ARRAY); + writeByte(PROPERTY_DOUBLE); + writeDoubles((double[]) obj); + } else if (componentType == Integer.TYPE) { + writeByte(PROPERTY_ARRAY); + writeByte(PROPERTY_INT); + writeInts((int[]) obj); + } else { + writeByte(PROPERTY_POOL); + writePoolObject(obj); + } + } else { + writeByte(PROPERTY_ARRAY); + writeByte(PROPERTY_POOL); + Object[] array = (Object[]) obj; + writeInt(array.length); + for (Object o : array) { + writePoolObject(o); + } + } + } else { + Graph g = findGraph(graph, obj); + if (g == null) { + writeByte(PROPERTY_POOL); + writePoolObject(obj); + } else { + writeByte(PROPERTY_SUBGRAPH); + writeGraph(g, null); + } + } + } + + private void writeProperties(Graph graph, Map props) throws IOException { + if (props == null) { + writeShort((char) 0); + return; + } + final int size = props.size(); + // properties + writeShort((char) size); + int cnt = 0; + for (Map.Entry entry : props.entrySet()) { + String key = entry.getKey().toString(); + writePoolObject(key); + writePropertyObject(graph, entry.getValue()); + cnt++; + } + if (size != cnt) { + throw new IOException("Expecting " + size + " properties, but found only " + cnt); + } + } + + private static final class ConstantPool extends LinkedHashMap { + + private final LinkedList availableIds; + private char nextId; + private static final long serialVersionUID = -2676889957907285681L; + + ConstantPool() { + super(50, 0.65f); + availableIds = new LinkedList<>(); + } + + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + if (size() > CONSTANT_POOL_MAX_SIZE) { + availableIds.addFirst(eldest.getValue()); + return true; + } + return false; + } + + private Character nextAvailableId() { + if (!availableIds.isEmpty()) { + return availableIds.removeFirst(); + } + return nextId++; + } + + public char add(Object obj) { + Character id = nextAvailableId(); + put(obj, id); + return id; + } + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphStructure.java 2017-08-03 22:43:02.138939408 -0700 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2011, 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.graphio; + +import java.util.Collection; +import java.util.Map; + +/** + * Interface that defines structure of a compiler graph. The structure of a graph is composed from + * nodes with properties, the classes of individual nodes, and ports associated with each node that + * may contain edges to other nodes. The structure of a graph is assumed to be immutable for the + * time of {@link GraphOutput operations} on it. + * + * @param the type of the (root node of a) graph + * @param the type of nodes + * @param the type of node classes + * @param

the type of node ports + */ +public interface GraphStructure { + /** + * Casts the provided object to graph, if possible. If the given object obj can be + * seen as a graph or sub-graph of a graph, then return the properly typed instance. Otherwise + * return null + * + * @param currentGraph the currently processed graph + * @param obj an object to check and view as a graph + * @return appropriate graph object or null if the object doesn't represent a graph + */ + G graph(G currentGraph, Object obj); + + /** + * Nodes of a graph. Each graph is composed from a fixed set of nodes. This method returns an + * iterable which provides access to all of them - the number of nodes provided by the iterable + * must match the number returned by {@link #nodesCount(java.lang.Object)} method. + * + * @see #nodesCount(java.lang.Object) + * @param graph the graph to query for nodes + * @return iterable with all the graph's nodes + */ + Iterable nodes(G graph); + + /** + * Number of nodes in a graph. The number must match the content returned by + * {@link #nodes(java.lang.Object)} method. + * + * @param graph the graph to query + * @return the number of nodes that will be returned by {@link #nodes(java.lang.Object)} + */ + int nodesCount(G graph); + + /** + * Id of a node. Each node in the graph is uniquely identified by a integer value. If two nodes + * have the same id, then they shall be == to each other. + * + * @param node the node to query for an id + * @return the id of the node + */ + int nodeId(N node); + + /** + * Checks if there is a predecessor for a node. + * + * @param node the node to check + * @return true if it has a predecessor, false otherwise + */ + boolean nodeHasPredecessor(N node); + + /** + * Collects node properties. Each node can be associated with additional properties identified + * by their name. This method shall copy them into the provided map. + * + * @param graph the current graph + * @param node the node to collect properties for + * @param properties the map to put the properties to + */ + void nodeProperties(G graph, N node, Map properties); + + /** + * Finds the node class for the provided object, if possible. If the given object + * obj can be seen as an instance of node class or it is a node in this graph, + * return the properly typed instance of the node class. Otherwise return null + * + * @param obj an object to find node class for + * @return appropriate graph object or null if the object doesn't represent a graph + */ + C nodeClass(Object obj); + + /** + * The template used to build the name of nodes of this class. The template may use references + * to inputs ({i#inputName}) and its properties ({p#propertyName}). + * + * @param nodeClass the node class to find name template for + * @return the string representing the template + */ + String nameTemplate(C nodeClass); + + /** + * Java class for a node class. + * + * @param nodeClass the node class + * @return the {@link Class} or other type representation of the node class + */ + Object nodeClassType(C nodeClass); + + /** + * Input ports of a node class. Each node class has a fixed set of ports where individual edges + * can attach to. + * + * @param nodeClass the node class + * @return input ports for the node class + */ + P portInputs(C nodeClass); + + /** + * Output ports of a node class. Each node class has a fixed set of ports from where individual + * edges can point to other nodes. + * + * @param nodeClass the node class + * @return output ports for the node class + */ + P portOutputs(C nodeClass); + + /** + * The number of edges in a port. The protocol will then call methods + * {@link #edgeDirect(java.lang.Object, int)}, {@link #edgeName(java.lang.Object, int)}, + * {@link #edgeType(java.lang.Object, int)} and + * {@link #edgeNodes(java.lang.Object, java.lang.Object, java.lang.Object, int)} for indexes + * from 0 to portSize - 1 + * + * @param port the port + * @return number of edges in this port + */ + int portSize(P port); + + /** + * Checks whether an edge is direct. Direct edge shall have exactly one + * {@linkplain #edgeNodes(java.lang.Object, java.lang.Object, java.lang.Object, int) node} - it + * is an error to return more than one for such an edge from the + * {@linkplain #edgeNodes(java.lang.Object, java.lang.Object, java.lang.Object, int) method}. + * + * @param port the port + * @param index index from 0 to {@link #portSize(java.lang.Object)} minus + * 1 + * @return true if only one node can be returned from + * {@link #edgeNodes(java.lang.Object, java.lang.Object, java.lang.Object, int)} method + */ + boolean edgeDirect(P port, int index); + + /** + * The name of an edge. + * + * @param port the port + * @param index index from 0 to {@link #portSize(java.lang.Object)} minus + * 1 + * @return the name of the edge + */ + String edgeName(P port, int index); + + /** + * Type of an edge. The type must be a graph + * enum - e.g. either real instance of {@link Enum} subclass, or something that the + * {@link GraphOutput.Builder} can recognize as + * enum. + * + * @param port + * @param index index from 0 to {@link #portSize(java.lang.Object)} minus + * 1 + * @return any {@link Enum} representing type of the edge + */ + Object edgeType(P port, int index); + + /** + * Nodes where the edges for a port lead to/from. This method is called for both + * {@link #edgeDirect(java.lang.Object, int) direct/non-direct edges}. In case of a direct edge + * the returned collection must have exactly one element. + * + * @param graph the graph + * @param node the node in the graph + * @param port port of the node class + * @param index index from 0 to {@link #portSize(java.lang.Object)} minus + * 1 + * @return null if there are no edges associated with given port or collection of + * nodes where to/from the edges lead to + */ + Collection edgeNodes(G graph, N node, P port, int index); +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphTypes.java 2017-08-03 22:43:02.450953396 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, 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.graphio; + +/** + * Special support for dealing with enums. Normally one can represent various {@link GraphOutput + * graph} enum values with real {@link Enum} instances. In case this is not possible, the + * {@link GraphOutput.Builder} allows one to + * {@link GraphOutput.Builder#types(org.graalvm.graphio.GraphTypes) register} an implementation of + * this interface to treat them specially. + */ +public interface GraphTypes { + /** + * Recognizes an + * enum object. If the enumValue object represents an enum, then an object + * that represents its class shall be returned. + * + * @param enumValue the value to test + * @return null if the value isn't enum, otherwise its class + */ + Object enumClass(Object enumValue); + + /** + * Ordinal of an enum. If the obj represents an enum, then return its ordinal + * number otherwise return -1 + * + * @param obj the value to test + * @return -1 if the obj isn't enum, otherwise its ordinal number + */ + int enumOrdinal(Object obj); + + /** + * All possible values of an enum. If the provided maybeEnumClass object represents + * an enum, then compute enum value names in ordinal order and return them as a string array. + * Otherwise return null + * + * @param maybeEnumClass the class to test + * @return null if the clazz isn't an enum, otherwise names of its values + */ + String[] enumTypeValues(Object maybeEnumClass); + + /** + * Finds Java type name for a given class. + * + * @param maybeClass object representing the class + * @return the type name of the class or null if the parameter doesn't represent a + * class + */ + String typeName(Object maybeClass); +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java 2017-08-03 22:43:02.769967698 -0700 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2011, 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.graphio; + +import java.io.IOException; +import java.nio.channels.WritableByteChannel; +import java.util.Collection; +import java.util.Map; + +final class ProtocolImpl + extends GraphProtocol { + private final GraphStructure structure; + private final GraphTypes types; + private final GraphBlocks blocks; + private final GraphElements elements; + + ProtocolImpl(GraphStructure structure, GraphTypes enums, GraphBlocks blocks, + GraphElements elements, WritableByteChannel channel) throws IOException { + super(channel); + this.structure = structure; + this.types = enums; + this.blocks = blocks; + this.elements = elements; + } + + @Override + protected Graph findGraph(Graph current, Object obj) { + return structure.graph(current, obj); + } + + @Override + protected NodeClass findNodeClass(Object obj) { + return structure.nodeClass(obj); + } + + @Override + protected String findNameTemplate(NodeClass clazz) { + return structure.nameTemplate(clazz); + } + + @Override + protected int findNodeId(Node n) { + return structure.nodeId(n); + } + + @Override + protected boolean hasPredecessor(Node node) { + return structure.nodeHasPredecessor(node); + } + + @Override + protected int findNodesCount(Graph info) { + return structure.nodesCount(info); + } + + @Override + protected Iterable findNodes(Graph info) { + return structure.nodes(info); + } + + @Override + protected void findNodeProperties(Node node, Map props, Graph info) { + structure.nodeProperties(info, node, props); + } + + @Override + protected Port findClassEdges(NodeClass nodeClass, boolean dumpInputs) { + if (dumpInputs) { + return structure.portInputs(nodeClass); + } else { + return structure.portOutputs(nodeClass); + } + } + + @Override + protected int findSize(Port edges) { + return structure.portSize(edges); + } + + @Override + protected boolean isDirect(Port edges, int i) { + return structure.edgeDirect(edges, i); + } + + @Override + protected String findName(Port edges, int i) { + return structure.edgeName(edges, i); + } + + @Override + protected Object findType(Port edges, int i) { + return structure.edgeType(edges, i); + } + + @Override + protected Collection findNodes(Graph graph, Node node, Port port, int i) { + return structure.edgeNodes(graph, node, port, i); + } + + @Override + protected Object findJavaClass(NodeClass clazz) { + return structure.nodeClassType(clazz); + } + + @Override + protected Object findEnumClass(Object enumValue) { + return types.enumClass(enumValue); + } + + @Override + protected int findEnumOrdinal(Object obj) { + return types.enumOrdinal(obj); + } + + @Override + protected String[] findEnumTypeValues(Object clazz) { + return types.enumTypeValues(clazz); + } + + @Override + protected String findJavaTypeName(Object obj) { + return types.typeName(obj); + } + + @Override + protected Collection findBlockNodes(Graph info, Block block) { + return blocks.blockNodes(info, block); + } + + @Override + protected int findBlockId(Block block) { + return blocks.blockId(block); + } + + @Override + protected Collection findBlocks(Graph graph) { + return blocks.blocks(graph); + } + + @Override + protected Collection findBlockSuccessors(Block block) { + return blocks.blockSuccessors(block); + } + + @Override + protected ResolvedJavaMethod findMethod(Object obj) { + return elements == null ? null : elements.method(obj); + } + + @Override + protected byte[] findMethodCode(ResolvedJavaMethod method) { + return elements.methodCode(method); + } + + @Override + protected int findMethodModifiers(ResolvedJavaMethod method) { + return elements.methodModifiers(method); + } + + @Override + protected Signature findMethodSignature(ResolvedJavaMethod method) { + return elements.methodSignature(method); + } + + @Override + protected String findMethodName(ResolvedJavaMethod method) { + return elements.methodName(method); + } + + @Override + protected Object findMethodDeclaringClass(ResolvedJavaMethod method) { + return elements.methodDeclaringClass(method); + } + + @Override + protected int findFieldModifiers(ResolvedJavaField field) { + return elements.fieldModifiers(field); + } + + @Override + protected String findFieldTypeName(ResolvedJavaField field) { + return elements.fieldTypeName(field); + } + + @Override + protected String findFieldName(ResolvedJavaField field) { + return elements.fieldName(field); + } + + @Override + protected Object findFieldDeclaringClass(ResolvedJavaField field) { + return elements.fieldDeclaringClass(field); + } + + @Override + protected ResolvedJavaField findJavaField(Object object) { + return elements == null ? null : elements.field(object); + } + + @Override + protected Signature findSignature(Object object) { + return elements == null ? null : elements.signature(object); + } + + @Override + protected int findSignatureParameterCount(Signature signature) { + return elements.signatureParameterCount(signature); + } + + @Override + protected String findSignatureParameterTypeName(Signature signature, int index) { + return elements.signatureParameterTypeName(signature, index); + } + + @Override + protected String findSignatureReturnTypeName(Signature signature) { + return elements.signatureReturnTypeName(signature); + } + + @Override + protected NodeSourcePosition findNodeSourcePosition(Object object) { + return elements == null ? null : elements.nodeSourcePosition(object); + } + + @Override + protected ResolvedJavaMethod findNodeSourcePositionMethod(NodeSourcePosition pos) { + return elements.nodeSourcePositionMethod(pos); + } + + @Override + protected NodeSourcePosition findNodeSourcePositionCaller(NodeSourcePosition pos) { + return elements.nodeSourcePositionCaller(pos); + } + + @Override + protected int findNodeSourcePositionBCI(NodeSourcePosition pos) { + return elements.nodeSourcePositionBCI(pos); + } + + @Override + protected StackTraceElement findMethodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { + return elements.methodStackTraceElement(method, bci, pos); + } + + @Override + protected void findExtraNodes(Node node, Collection extraNodes) { + } + + @Override + protected String formatTitle(Graph graph, int id, String format, Object... args) { + return String.format(format, args) + " [" + id + "]"; + } +}