--- a/hotspot/src/jdk.internal.vm.compiler/.mx.graal/suite.py Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/.mx.graal/suite.py Fri Aug 04 19:59:33 2017 -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",
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java Fri Aug 04 19:59:33 2017 -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));
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java Fri Aug 04 19:59:33 2017 -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));
- }
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java Fri Aug 04 19:59:33 2017 -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<Boolean> UseSnippetGraphCache = new OptionKey<>(true);
- @Option(help = "Enable expensive assertions.", type = OptionType.Debug)
- public static final OptionKey<Boolean> DetailedAsserts = new OptionKey<>(Assertions.ENABLED);
-
@Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Fri Aug 04 19:59:33 2017 -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()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ZeroSignExtendTest.java Fri Aug 04 19:59:33 2017 -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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/CountUppercaseParallelTest.java Fri Aug 04 19:59:33 2017 -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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTreesTest.java Fri Aug 04 19:59:33 2017 -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<TreeNode> instances) {
+ instances.add(this);
+ if (left != null) {
+ left.visit(instances);
+ }
+ if (right != null) {
+ right.visit(instances);
+ }
+ }
+
+ int countInstances() {
+ HashSet<TreeNode> 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);
+ }
+ }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java Fri Aug 04 19:59:33 2017 -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");
+ }
+
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java Fri Aug 04 19:59:33 2017 -0700
@@ -227,7 +227,7 @@
*/
@Test
public void testInvariantChecking() throws InterruptedException {
- Assume.assumeTrue(Assertions.ENABLED);
+ Assume.assumeTrue(Assertions.assertionsEnabled());
EconomicMap<OptionKey<?>, Object> map = EconomicMap.create();
// Configure with an option that enables counters
map.put(DebugOptions.Counters, "");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Assertions.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Assertions.java Fri Aug 04 19:59:33 2017 -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<Boolean> DetailedAsserts = new OptionKey<>(true);
+
+ }
+ // @formatter:on
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java Fri Aug 04 19:59:33 2017 -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;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Fri Aug 04 19:59:33 2017 -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();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Fri Aug 04 19:59:33 2017 -0700
@@ -75,7 +75,7 @@
public static final OptionKey<String> 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<String> Verify = new OptionKey<>(Assertions.ENABLED ? "" : null);
+ public static final OptionKey<String> 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<String> 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<String> DumpPath = new OptionKey<>("dumps");
@Option(help = "Print the name of each dump file path as it's created.")
- public static final OptionKey<Boolean> ShowDumpFiles = new OptionKey<>(Assertions.ENABLED);
+ public static final OptionKey<Boolean> ShowDumpFiles = new OptionKey<>(false);
@Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintCFG = new OptionKey<>(false);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java Fri Aug 04 19:59:33 2017 -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();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java Fri Aug 04 19:59:33 2017 -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) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java Fri Aug 04 19:59:33 2017 -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;
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesCreator.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesCreator.java Fri Aug 04 19:59:33 2017 -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;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Fri Aug 04 19:59:33 2017 -0700
@@ -82,6 +82,8 @@
"test");
}
+ private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose");
+
private static void testHelper(List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
final File dumpPath = new File(CompilationWrapperTest.class.getSimpleName() + "_" + System.currentTimeMillis()).getAbsoluteFile();
List<String> 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 ";
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Fri Aug 04 19:59:33 2017 -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);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Fri Aug 04 19:59:33 2017 -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<CompilerConfigurationFactory> factories = Assertions.ENABLED ? new ArrayList<>() : null;
+ private static final List<CompilerConfigurationFactory> factories = Assertions.assertionsEnabled() ? new ArrayList<>() : null;
private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) {
for (CompilerConfigurationFactory other : factories) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java Fri Aug 04 19:59:33 2017 -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;
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java Fri Aug 04 19:59:33 2017 -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 {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java Fri Aug 04 19:59:33 2017 -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);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java Fri Aug 04 19:59:33 2017 -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,
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Fri Aug 04 19:59:33 2017 -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);
+ }
}
/**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java Fri Aug 04 19:59:33 2017 -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;
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java Fri Aug 04 19:59:33 2017 -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() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java Fri Aug 04 19:59:33 2017 -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);
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Fri Aug 04 19:59:33 2017 -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";
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java Fri Aug 04 19:59:33 2017 -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";
/*
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java Fri Aug 04 19:59:33 2017 -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;
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java Fri Aug 04 19:59:33 2017 -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()) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java Fri Aug 04 19:59:33 2017 -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) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java Fri Aug 04 19:59:33 2017 -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";
/*
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Fri Aug 04 19:59:33 2017 -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.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java Fri Aug 04 19:59:33 2017 -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());
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java Fri Aug 04 19:59:33 2017 -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();
- }
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Fri Aug 04 19:59:33 2017 -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;
+ return 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 false;
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java Fri Aug 04 19:59:33 2017 -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);
}
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java Fri Aug 04 19:59:33 2017 -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<LoopBeginNode> 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);
+ }
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java Fri Aug 04 19:59:33 2017 -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<Block> 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() {
+ public boolean reassociateInvariants() {
+ int count = 0;
+ StructuredGraph graph = loopBegin().graph();
InvariantPredicate invariant = new InvariantPredicate();
- StructuredGraph graph = loopBegin().graph();
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) {
+ 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);
}
- if (!result.isAlive()) {
- assert !result.isDeleted();
- result = graph.addOrUniqueWithInputs(result);
- }
binary.replaceAtUsages(result);
GraphUtil.killWithUnusedFloatingInputs(binary);
+ count++;
}
}
+ return count != 0;
}
public boolean detectCounted() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java Fri Aug 04 19:59:33 2017 -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<Node> 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 ?
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Fri Aug 04 19:59:33 2017 -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
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java Fri Aug 04 19:59:33 2017 -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();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java Fri Aug 04 19:59:33 2017 -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<FixedValueAnchorNode> TYPE = NodeClass.create(FixedValueAnchorNode.class);
@Input ValueNode object;
@@ -45,9 +45,13 @@
return object;
}
+ protected FixedValueAnchorNode(NodeClass<? extends FixedValueAnchorNode> c, ValueNode object) {
+ super(c, object.stamp());
+ this.object = object;
+ }
+
public FixedValueAnchorNode(ValueNode object) {
- super(TYPE, object.stamp());
- this.object = object;
+ this(TYPE, object);
}
public FixedValueAnchorNode(ValueNode object, Stamp predefinedStamp) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java Fri Aug 04 19:59:33 2017 -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/StateSplitProxyNode.java Fri Aug 04 19:59:33 2017 -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<StateSplitProxyNode> 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;
+ }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java Fri Aug 04 19:59:33 2017 -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<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java Fri Aug 04 19:59:33 2017 -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.";
+ }
}
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java Fri Aug 04 19:59:33 2017 -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));
+
+ }
+
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java Fri Aug 04 19:59:33 2017 -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<OptionKey<?>, 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<OptionKey<?>, 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));
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Fri Aug 04 19:59:33 2017 -0700
@@ -52,7 +52,7 @@
public OptionValues(OptionValues initialValues, UnmodifiableEconomicMap<OptionKey<?>, Object> extraPairs) {
EconomicMap<OptionKey<?>, Object> map = newOptionMap();
if (initialValues != null) {
- map.putAll(initialValues.values);
+ map.putAll(initialValues.getMap());
}
initMap(map, extraPairs);
this.values = map;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java Fri Aug 04 19:59:33 2017 -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;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java Fri Aug 04 19:59:33 2017 -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());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java Fri Aug 04 19:59:33 2017 -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;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java Fri Aug 04 19:59:33 2017 -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<MicroBlock> nodeToBlock, NodeBitMap visited) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java Fri Aug 04 19:59:33 2017 -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'};
+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;
- private void writeVersion() throws IOException {
- writeBytesRaw(MAGIC_BYTES);
- writeByte(CURRENT_MAJOR_VERSION);
- writeByte(CURRENT_MINOR_VERSION);
- }
-
- private static final class ConstantPool extends LinkedHashMap<Object, Character> {
-
- private final LinkedList<Character> 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<Object, Character> 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;
+public class BinaryGraphPrinter implements
+ GraphStructure<BinaryGraphPrinter.GraphInfo, Node, NodeClass<?>, Edges>,
+ GraphBlocks<BinaryGraphPrinter.GraphInfo, Block, Node>,
+ GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition>,
+ GraphTypes, GraphPrinter {
private final SnippetReflectionProvider snippetReflection;
-
- private static final Charset utf8 = Charset.forName("UTF-8");
+ private final GraphOutput<BinaryGraphPrinter.GraphInfo, ResolvedJavaMethod> 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,339 +89,174 @@
return snippetReflection;
}
- @SuppressWarnings("all")
@Override
- public void print(DebugContext debug, Graph graph, Map<Object, Object> 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);
- }
- } else {
- writePoolObject(id + ": " + String.format(format, simplifyClassArgs(args)));
- }
- writeGraph(debug, graph, properties);
- flush();
- }
-
- private void writeGraph(DebugContext debug, Graph graph, Map<Object, Object> 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<List<Node>> blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap();
- NodeMap<Block> nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap();
- List<Block> blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks());
- writeProperties(debug, properties);
- writeNodes(debug, graph, nodeToBlocks, cfg);
- writeBlocks(blocks, blockToNodes);
+ public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException {
+ output.beginGroup(new GraphInfo(debug, null), name, shortName, method, bci, properties);
}
- 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();
- }
- }
- 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);
+ @Override
+ public void endGroup() throws IOException {
+ output.endGroup();
}
- 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;
- }
+ @Override
+ public void close() {
+ output.close();
}
- 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);
+ @Override
+ public ResolvedJavaMethod method(Object object) {
+ if (object instanceof Bytecode) {
+ return ((Bytecode) object).getMethod();
+ } else if (object instanceof ResolvedJavaMethod) {
+ return ((ResolvedJavaMethod) object);
} 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<?>) {
- 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);
- }
- writeShort(id.charValue());
+ return null;
}
}
- private static String getClassName(Class<?> klass) {
- if (!klass.isArray()) {
- return klass.getName();
+ @Override
+ public NodeClass<?> nodeClass(Object obj) {
+ if (obj instanceof NodeClass<?>) {
+ return (NodeClass<?>) obj;
}
- return getClassName(klass.getComponentType()) + "[]";
+ if (obj instanceof Node) {
+ return ((Node) obj).getNodeClass();
+ }
+ return null;
}
- @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());
+ @Override
+ public Object nodeClassType(NodeClass<?> node) {
+ return node.getJavaClass();
+ }
+
+ @Override
+ public String nameTemplate(NodeClass<?> nodeClass) {
+ return nodeClass.getNameTemplate();
+ }
+
+ @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 {
- writeByte(POOL_STRING);
- writeString(object.toString());
+ return null;
}
}
- 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));
- }
- }
+ @Override
+ public int nodeId(Node n) {
+ return getNodeId(n);
}
- 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);
- }
- }
- } else {
- writeByte(PROPERTY_POOL);
- writePoolObject(obj);
- }
+ @Override
+ public Edges portInputs(NodeClass<?> nodeClass) {
+ return nodeClass.getEdges(Inputs);
+ }
+
+ @Override
+ public Edges portOutputs(NodeClass<?> nodeClass) {
+ return nodeClass.getEdges(Successors);
}
@SuppressWarnings("deprecation")
private static int getNodeId(Node node) {
- return node.getId();
+ return node == null ? -1 : node.getId();
+ }
+
+ @Override
+ public List<Node> blockNodes(GraphInfo info, Block block) {
+ List<Node> nodes = info.blockToNodes.get(block);
+ if (nodes == null) {
+ return null;
+ }
+ List<Node> extraNodes = new LinkedList<>();
+ for (Node node : nodes) {
+ findExtraNodes(node, extraNodes);
+ }
+ extraNodes.removeAll(nodes);
+ extraNodes.addAll(0, nodes);
+ return extraNodes;
+ }
+
+ @Override
+ public int blockId(Block sux) {
+ return sux.getId();
+ }
+
+ @Override
+ public List<Block> blockSuccessors(Block block) {
+ return Arrays.asList(block.getSuccessors());
+ }
+
+ @Override
+ public Iterable<Node> nodes(GraphInfo info) {
+ return info.graph.getNodes();
+ }
+
+ @Override
+ public int nodesCount(GraphInfo info) {
+ return info.graph.getNodeCount();
+ }
+
+ @Override
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public void nodeProperties(GraphInfo info, Node node, Map<String, Object> props) {
+ node.getDebugProperties((Map) props);
+ Graph graph = info.graph;
+ ControlFlowGraph cfg = info.cfg;
+ NodeMap<Block> 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);
+ }
+ }
+
+ try {
+ props.put("NodeCost-Size", node.estimatedNodeSize());
+ props.put("NodeCost-Cycles", node.estimatedNodeCycles());
+ } catch (Throwable t) {
+ props.put("node-cost-exception", t.getMessage());
+ }
+
+ if (nodeToBlocks != null) {
+ Object block = getBlockForNode(node, nodeToBlocks);
+ if (block != null) {
+ props.put("node-to-block", block);
+ }
+ }
+
+ 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((Map) props, cn);
+ }
+ props.put("category", "floating");
+ }
}
private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) {
@@ -516,181 +273,243 @@
return null;
}
- private void writeNodes(DebugContext debug, Graph graph, NodeMap<Block> nodeToBlocks, ControlFlowGraph cfg) throws IOException {
- Map<Object, Object> props = new HashMap<>();
-
- writeInt(graph.getNodeCount());
-
- 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);
- }
- }
-
- try {
- props.put("NodeCost-Size", node.estimatedNodeSize());
- props.put("NodeCost-Cycles", node.estimatedNodeCycles());
- } catch (Throwable t) {
- props.put("node-cost-exception", t.getMessage());
- }
-
- if (nodeToBlocks != null) {
- Object block = getBlockForNode(node, nodeToBlocks);
- if (block != null) {
- props.put("node-to-block", block);
- }
- }
-
- 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");
- }
-
- writeInt(getNodeId(node));
- writePoolObject(nodeClass);
- writeByte(node.predecessor() == null ? 0 : 1);
- writeProperties(debug, props);
- writeEdges(node, Inputs);
- writeEdges(node, Successors);
-
- props.clear();
- }
- }
-
- private void writeProperties(DebugContext debug, Map<Object, Object> props) throws IOException {
- if (props == null) {
- writeShort((char) 0);
- return;
- }
- // properties
- writeShort((char) props.size());
- for (Entry<Object, Object> entry : props.entrySet()) {
- String key = entry.getKey().toString();
- writePoolObject(key);
- writePropertyObject(debug, entry.getValue());
- }
- }
-
- 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<Node> 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);
- }
+ private static void findExtraNodes(Node node, Collection<? super Node> extraNodes) {
+ if (node instanceof AbstractMergeNode) {
+ AbstractMergeNode merge = (AbstractMergeNode) node;
+ for (PhiNode phi : merge.phis()) {
+ extraNodes.add(phi);
}
}
}
- private void writeNodeRef(Node edge) throws IOException {
- if (edge != null) {
- writeInt(getNodeId(edge));
- } else {
- writeInt(-1);
- }
+ @Override
+ public boolean nodeHasPredecessor(Node node) {
+ return node.predecessor() != null;
+ }
+
+ @Override
+ public List<Block> blocks(GraphInfo graph) {
+ return graph.blocks;
+ }
+
+ @Override
+ public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException {
+ output.print(new GraphInfo(debug, graph), properties, id, format, args);
+ }
+
+ @Override
+ public int portSize(Edges port) {
+ return port.getCount();
}
- private void writeBlocks(List<Block> blocks, BlockMap<List<Node>> blockToNodes) throws IOException {
- if (blocks != null && blockToNodes != null) {
- for (Block block : blocks) {
- List<Node> nodes = blockToNodes.get(block);
- if (nodes == null) {
- writeInt(0);
- return;
- }
- }
- writeInt(blocks.size());
- for (Block block : blocks) {
- List<Node> nodes = blockToNodes.get(block);
- List<Node> 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());
- }
- }
+ @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);
+ }
+
+ @Override
+ public Collection<? extends Node> 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 {
- writeInt(0);
+ return Edges.getNodeList(node, port.getOffsets(), i);
}
}
@Override
- public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException {
- writeByte(BEGIN_GROUP);
- writePoolObject(name);
- writePoolObject(shortName);
- writePoolObject(method);
- writeInt(bci);
- writeProperties(debug, properties);
+ public Object 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<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) 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 obj) {
+ if (obj instanceof Class<?>) {
+ return ((Class<?>) obj).getName();
+ }
+ if (obj instanceof ResolvedJavaType) {
+ return ((ResolvedJavaType) obj).getName();
+ }
+ return null;
+ }
+
+ @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 void endGroup() throws IOException {
- writeByte(CLOSE_GROUP);
+ public ResolvedJavaField field(Object object) {
+ if (object instanceof ResolvedJavaField) {
+ return (ResolvedJavaField) object;
+ }
+ return null;
+ }
+
+ @Override
+ public Signature signature(Object object) {
+ if (object instanceof Signature) {
+ return (Signature) object;
+ }
+ return null;
+ }
+
+ @Override
+ public int signatureParameterCount(Signature signature) {
+ return signature.getParameterCount(false);
+ }
+
+ @Override
+ 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 void close() {
- try {
- flush();
- channel.close();
- } catch (IOException ex) {
- throw new Error(ex);
+ 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<List<Node>> blockToNodes;
+ final NodeMap<Block> nodeToBlocks;
+ final List<Block> 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());
}
}
+
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java Fri Aug 04 19:59:33 2017 -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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadNode.java Fri Aug 04 19:59:33 2017 -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<AArch64ReadNode> 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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadReplacementPhase.java Fri Aug 04 19:59:33 2017 -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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnVolatileReadTest.java Fri Aug 04 19:59:33 2017 -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());
+ }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java Fri Aug 04 19:59:33 2017 -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
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java Fri Aug 04 19:59:33 2017 -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();
}
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java Fri Aug 04 19:59:33 2017 -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<PEReadEliminationBlockState> {
final EconomicMap<ReadCacheEntry, ValueNode> 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();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Fri Aug 04 19:59:33 2017 -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<ValueNode, Object> 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<ValueNode, Object>) pair.getRight();
}
}
@@ -307,7 +310,7 @@
MapCursor<ReadCacheEntry, ValueNode> 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<PEReadEliminationBlockState> states) {
+ private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List<PEReadEliminationBlockState> 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);
}
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java Fri Aug 04 19:59:33 2017 -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 <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
- if (left.size() != right.size()) {
- return false;
- }
- return compareMapsNoSize(left, right);
- }
-
- protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) {
- if (left == right) {
- return true;
- }
- for (Map.Entry<K, V> 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 <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) {
- Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry<U, V> 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];
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Fri Aug 04 19:59:33 2017 -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;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/DefaultGraphBlocks.java Fri Aug 04 19:59:33 2017 -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<Object, Object, Object> {
+ private static final DefaultGraphBlocks DEFAULT = new DefaultGraphBlocks();
+
+ private DefaultGraphBlocks() {
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <G, B, N> GraphBlocks<G, B, N> empty() {
+ return (GraphBlocks<G, B, N>) DEFAULT;
+ }
+
+ @Override
+ public Collection<? extends Void> blocks(Object graph) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public int blockId(Object block) {
+ return -1;
+ }
+
+ @Override
+ public Collection<? extends Object> blockNodes(Object info, Object block) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection<? extends Object> blockSuccessors(Object block) {
+ return Collections.emptyList();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/DefaultGraphTypes.java Fri Aug 04 19:59:33 2017 -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<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) 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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphBlocks.java Fri Aug 04 19:59:33 2017 -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 <G> the type that represents the graph
+ * @param <B> the type that represents the block
+ * @param <N> the type of the node
+ */
+public interface GraphBlocks<G, B, N> {
+ /**
+ * All blocks in the graph.
+ *
+ * @param graph the graph
+ * @return collection of blocks in the graph
+ */
+ Collection<? extends B> blocks(G graph);
+
+ /**
+ * Unique id of a block.
+ *
+ * @param block the block
+ * @return the id of the block
+ */
+ int blockId(B block);
+
+ Collection<? extends N> blockNodes(G info, B block);
+
+ Collection<? extends B> blockSuccessors(B block);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphElements.java Fri Aug 04 19:59:33 2017 -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 <M> type representing methods
+ * @param <F> type representing fields
+ * @param <S> type representing signature
+ * @param <P> type representing source code location
+ */
+public interface GraphElements<M, F, S, P> {
+ /**
+ * Recognize method. Can the object be seen as a method?
+ *
+ * @param obj the object to check
+ * @return <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java Fri Aug 04 19:59:33 2017 -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 <G> the type of graph this instance handles
+ * @param <M> the type of methods this instance handles
+ */
+public final class GraphOutput<G, M> implements Closeable {
+ private final GraphProtocol<G, ?, ?, ?, ?, M, ?, ?, ?> printer;
+
+ private GraphOutput(GraphProtocol<G, ?, ?, ?, ?, M, ?, ?, ?> p) {
+ this.printer = p;
+ }
+
+ /**
+ * Creates new builder to configure a future instance of {@link GraphOutput}.
+ *
+ * @param <G> the type of the graph
+ * @param <N> the type of the nodes
+ * @param <C> the type of the node classes
+ * @param <P> the type of the ports
+ *
+ * @param structure description of the structure of the graph
+ * @return the builder to configure
+ */
+ public static <G, N, C, P> Builder<G, N, ?> newBuilder(GraphStructure<G, N, C, P> 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<? extends Object, ? extends Object> 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<? extends Object, ? extends Object> 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 <G> the type of the (root element of) graph
+ * @param <N> the type of the nodes
+ * @param <M> the type of the methods
+ */
+ public static final class Builder<G, N, M> {
+ private final GraphStructure<G, N, ?, ?> structure;
+ private GraphElements<M, ?, ?, ?> elements = null;
+ private GraphTypes types = DefaultGraphTypes.DEFAULT;
+ private GraphBlocks<G, ?, N> blocks = DefaultGraphBlocks.empty();
+
+ Builder(GraphStructure<G, N, ?, ?> structure) {
+ this.structure = structure;
+ }
+
+ /**
+ * Associates different implementation of types.
+ *
+ * @param graphTypes implementation of types and enum recognition
+ * @return this builder
+ */
+ public Builder<G, N, M> types(GraphTypes graphTypes) {
+ this.types = graphTypes;
+ return this;
+ }
+
+ /**
+ * Associates implementation of blocks.
+ *
+ * @param graphBlocks the blocks implementation
+ * @return this builder
+ */
+ public Builder<G, N, M> blocks(GraphBlocks<G, ?, N> graphBlocks) {
+ this.blocks = graphBlocks;
+ return this;
+ }
+
+ /**
+ * Associates implementation of graph elements.
+ *
+ * @param graphElements the elements implementation
+ * @return this builder
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public <E> Builder<G, N, E> elements(GraphElements<E, ?, ?, ?> graphElements) {
+ this.elements = (GraphElements) graphElements;
+ return (Builder<G, N, E>) 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<G, M> build(WritableByteChannel channel) throws IOException {
+ ProtocolImpl<G, N, ?, ?, ?, M, ?, ?, ?> p = new ProtocolImpl<>(structure, types, blocks, elements, channel);
+ return new GraphOutput<>(p);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Fri Aug 04 19:59:33 2017 -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<Graph, Node, NodeClass, Edges, Block, ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> 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<? extends Object, ? extends Object> 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<? extends Object, ? extends Object> 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<? super Node> extraNodes);
+
+ protected abstract boolean hasPredecessor(Node node);
+
+ protected abstract int findNodesCount(Graph info);
+
+ protected abstract Iterable<? extends Node> findNodes(Graph info);
+
+ protected abstract void findNodeProperties(Node node, Map<String, Object> props, Graph info);
+
+ protected abstract Collection<? extends Node> findBlockNodes(Graph info, Block block);
+
+ protected abstract int findBlockId(Block sux);
+
+ protected abstract Collection<? extends Block> findBlocks(Graph graph);
+
+ protected abstract Collection<? extends Block> 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<? extends Node> 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<? extends Object, ? extends Object> properties) throws IOException {
+ writeProperties(graph, properties);
+ writeNodes(graph);
+ writeBlocks(findBlocks(graph), graph);
+ }
+
+ private void writeNodes(Graph info) throws IOException {
+ Map<String, Object> 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<? extends Node> 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<? extends Block> blocks, Graph info) throws IOException {
+ if (blocks != null) {
+ for (Block block : blocks) {
+ Collection<? extends Node> nodes = findBlockNodes(info, block);
+ if (nodes == null) {
+ writeInt(0);
+ return;
+ }
+ }
+ writeInt(blocks.size());
+ for (Block block : blocks) {
+ Collection<? extends Node> nodes = findBlockNodes(info, block);
+ writeInt(findBlockId(block));
+ writeInt(nodes.size());
+ for (Node node : nodes) {
+ writeInt(findNodeId(node));
+ }
+ final Collection<? extends Block> 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<? extends Object, ? extends Object> 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<? extends Object, ? extends Object> 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<Object, Character> {
+
+ private final LinkedList<Character> 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<Object, Character> 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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphStructure.java Fri Aug 04 19:59:33 2017 -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 <G> the type of the (root node of a) graph
+ * @param <N> the type of nodes
+ * @param <C> the type of node classes
+ * @param <P> the type of node ports
+ */
+public interface GraphStructure<G, N, C, P> {
+ /**
+ * Casts the provided object to graph, if possible. If the given object <code>obj</code> can be
+ * seen as a graph or sub-graph of a graph, then return the properly typed instance. Otherwise
+ * return <code>null</code>
+ *
+ * @param currentGraph the currently processed graph
+ * @param obj an object to check and view as a graph
+ * @return appropriate graph object or <code>null</code> 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<? extends N> 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 <code>==</code> 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 <code>true</code> if it has a predecessor, <code>false</code> 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<String, ? super Object> properties);
+
+ /**
+ * Finds the node class for the provided object, if possible. If the given object
+ * <code>obj</code> 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 <code>null</code>
+ *
+ * @param obj an object to find node class for
+ * @return appropriate graph object or <code>null</code> 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 <code>0</code> to <code>portSize - 1</code>
+ *
+ * @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 <code>0</code> to {@link #portSize(java.lang.Object)} minus
+ * <code>1</code>
+ * @return <code>true</code> 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 <code>0</code> to {@link #portSize(java.lang.Object)} minus
+ * <code>1</code>
+ * @return the name of the edge
+ */
+ String edgeName(P port, int index);
+
+ /**
+ * Type of an edge. The type must be a graph
+ * <q>enum</q> - e.g. either real instance of {@link Enum} subclass, or something that the
+ * {@link GraphOutput.Builder} can recognize as
+ * <q>enum</q>.
+ *
+ * @param port
+ * @param index index from <code>0</code> to {@link #portSize(java.lang.Object)} minus
+ * <code>1</code>
+ * @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 <code>0</code> to {@link #portSize(java.lang.Object)} minus
+ * <code>1</code>
+ * @return <code>null</code> if there are no edges associated with given port or collection of
+ * nodes where to/from the edges lead to
+ */
+ Collection<? extends N> edgeNodes(G graph, N node, P port, int index);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphTypes.java Fri Aug 04 19:59:33 2017 -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
+ * <q>enum</q> object. If the <code>enumValue</code> object represents an enum, then an object
+ * that represents its class shall be returned.
+ *
+ * @param enumValue the value to test
+ * @return <code>null</code> if the value isn't enum, otherwise its class
+ */
+ Object enumClass(Object enumValue);
+
+ /**
+ * Ordinal of an enum. If the <code>obj</code> represents an enum, then return its ordinal
+ * number otherwise return <code>-1</code>
+ *
+ * @param obj the value to test
+ * @return <code>-1</code> if the obj isn't enum, otherwise its ordinal number
+ */
+ int enumOrdinal(Object obj);
+
+ /**
+ * All possible values of an enum. If the provided <code>maybeEnumClass</code> object represents
+ * an enum, then compute enum value names in ordinal order and return them as a string array.
+ * Otherwise return <code>null</code>
+ *
+ * @param maybeEnumClass the class to test
+ * @return <code>null</code> 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 <code>null</code> if the parameter doesn't represent a
+ * class
+ */
+ String typeName(Object maybeClass);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java Fri Aug 04 19:59:33 2017 -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<Graph, Node, NodeClass, Port, Block, ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition>
+ extends GraphProtocol<Graph, Node, NodeClass, Port, Block, ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> {
+ private final GraphStructure<Graph, Node, NodeClass, Port> structure;
+ private final GraphTypes types;
+ private final GraphBlocks<Graph, Block, Node> blocks;
+ private final GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> elements;
+
+ ProtocolImpl(GraphStructure<Graph, Node, NodeClass, Port> structure, GraphTypes enums, GraphBlocks<Graph, Block, Node> blocks,
+ GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> 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<? extends Node> findNodes(Graph info) {
+ return structure.nodes(info);
+ }
+
+ @Override
+ protected void findNodeProperties(Node node, Map<String, Object> 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<? extends Node> 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<? extends Node> findBlockNodes(Graph info, Block block) {
+ return blocks.blockNodes(info, block);
+ }
+
+ @Override
+ protected int findBlockId(Block block) {
+ return blocks.blockId(block);
+ }
+
+ @Override
+ protected Collection<? extends Block> findBlocks(Graph graph) {
+ return blocks.blocks(graph);
+ }
+
+ @Override
+ protected Collection<? extends Block> 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<? super Node> extraNodes) {
+ }
+
+ @Override
+ protected String formatTitle(Graph graph, int id, String format, Object... args) {
+ return String.format(format, args) + " [" + id + "]";
+ }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java Sat Aug 05 03:05:06 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java Fri Aug 04 19:59:33 2017 -0700
@@ -151,15 +151,17 @@
public static <T> Builder newBuilder(OptionKey<T> 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;