8185829: Update Graal
Reviewed-by: iveresov
This commit is contained in:
parent
d67d35e00a
commit
4c46a93864
@ -179,6 +179,14 @@ suite = {
|
||||
"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 @@ suite = {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"org.graalvm.graphio",
|
||||
"org.graalvm.compiler.core",
|
||||
"org.graalvm.compiler.java",
|
||||
],
|
||||
@ -1138,6 +1147,13 @@ suite = {
|
||||
],
|
||||
},
|
||||
|
||||
"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 @@ suite = {
|
||||
"distDependencies" : [
|
||||
"GRAAL_API",
|
||||
"GRAAL_COMPILER",
|
||||
"GRAAL_GRAPHIO",
|
||||
],
|
||||
},
|
||||
|
||||
@ -1297,6 +1314,7 @@ suite = {
|
||||
"GRAAL" : {
|
||||
"subDir" : "share/classes",
|
||||
"overlaps" : [
|
||||
"GRAAL_GRAPHIO",
|
||||
"GRAAL_OPTIONS",
|
||||
"GRAAL_NODEINFO",
|
||||
"GRAAL_API",
|
||||
|
@ -94,7 +94,7 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -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 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public final class GraalOptions {
|
||||
@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);
|
||||
|
||||
|
@ -111,6 +111,7 @@ import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
|
||||
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 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
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 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
*/
|
||||
@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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,10 @@ public class UnsafeEATest extends EATestBase {
|
||||
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 @@ public class UnsafeEATest extends EATestBase {
|
||||
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 @@ public class UnsafeEATest extends EATestBase {
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ public class DebugContextTest {
|
||||
*/
|
||||
@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, "");
|
||||
|
@ -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 @@ public class Assertions {
|
||||
* 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
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ final class DebugConfigImpl implements DebugConfig {
|
||||
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 @@ final class DebugConfigImpl implements DebugConfig {
|
||||
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;
|
||||
|
@ -32,11 +32,9 @@ import static org.graalvm.compiler.debug.DebugOptions.DumpOnPhaseChange;
|
||||
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 @@ public final class DebugContext implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
}
|
||||
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 @@ public final class DebugContext implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -75,7 +75,7 @@ public class DebugOptions {
|
||||
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 @@ public class DebugOptions {
|
||||
@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);
|
||||
|
@ -148,7 +148,8 @@ public class DiagnosticsOutputDirectory {
|
||||
@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();
|
||||
|
@ -119,7 +119,7 @@ public class NodeMapTest extends GraphTest {
|
||||
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 @@ public class NodeMapTest extends GraphTest {
|
||||
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) {
|
||||
|
@ -31,9 +31,11 @@ import org.graalvm.compiler.phases.BasePhase;
|
||||
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 @@ public class AArch64HotSpotSuitesProvider extends HotSpotSuitesProvider {
|
||||
}
|
||||
findPhase.add(new AddressLoweringByUsePhase(addressLoweringByUse));
|
||||
|
||||
findPhase = suites.getLowTier().findPhase(PropagateDeoptimizeProbabilityPhase.class);
|
||||
findPhase.add(new AArch64ReadReplacementPhase());
|
||||
|
||||
return suites;
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public class AMD64HotSpotSuitesCreator extends AMD64SuitesCreator {
|
||||
@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;
|
||||
|
@ -82,6 +82,8 @@ public class CompilationWrapperTest extends GraalCompilerTest {
|
||||
"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 @@ public class CompilationWrapperTest extends GraalCompilerTest {
|
||||
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 ";
|
||||
|
@ -53,6 +53,7 @@ import jdk.vm.ci.hotspot.EventProvider;
|
||||
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 @@ public class CompilationTask {
|
||||
* 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 @@ public class CompilationTask {
|
||||
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);
|
||||
|
@ -130,7 +130,7 @@ public abstract class CompilerConfigurationFactory implements Comparable<Compile
|
||||
* 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) {
|
||||
|
@ -162,9 +162,20 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
* 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 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -138,8 +138,6 @@ class JVMCIVersionCheck {
|
||||
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 {
|
||||
|
@ -153,7 +153,7 @@ public class ExceptionHandlerStub extends SnippetStub {
|
||||
@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);
|
||||
|
@ -116,7 +116,7 @@ public class UnwindExceptionToCallerStub extends SnippetStub {
|
||||
@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,
|
||||
|
@ -371,6 +371,7 @@ import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
|
||||
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 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
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 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
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 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 java.util.List;
|
||||
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 @@ public final class Interval {
|
||||
// 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;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
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.LIRKind;
|
||||
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 @@ public class LinearScan {
|
||||
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() {
|
||||
|
@ -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 static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
|
||||
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 @@ public class LinearScanEliminateSpillMovePhase extends LinearScanAllocationPhase
|
||||
*/
|
||||
Interval interval;
|
||||
interval = allocator.createUnhandledLists(mustStoreAtDefinition, null).getLeft();
|
||||
if (DetailedAsserts.getValue(allocator.getOptions())) {
|
||||
if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) {
|
||||
checkIntervals(debug, interval);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
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.PermanentBailoutException;
|
||||
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 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase {
|
||||
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 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase {
|
||||
}
|
||||
} 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 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase {
|
||||
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";
|
||||
|
@ -26,7 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
|
||||
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.RegisterAllocationConfig.Allocatab
|
||||
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 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
|
||||
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";
|
||||
|
||||
/*
|
||||
|
@ -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 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 java.util.List;
|
||||
|
||||
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 @@ final class TraceInterval extends IntervalHint {
|
||||
|
||||
// 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 @@ final class TraceInterval extends IntervalHint {
|
||||
// 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;
|
||||
}
|
||||
|
@ -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.RegisterAllocationConfig;
|
||||
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 @@ final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAlloca
|
||||
* by Interval.spillDefinitionPos.
|
||||
*/
|
||||
TraceInterval interval = allocator.createUnhandledListBySpillPos(spilledIntervals);
|
||||
if (DetailedAsserts.getValue(allocator.getOptions())) {
|
||||
if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) {
|
||||
checkIntervals(debug, interval);
|
||||
}
|
||||
if (debug.isLogEnabled()) {
|
||||
|
@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
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.RegisterAllocationConfig;
|
||||
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 @@ public final class TraceLinearScanPhase extends TraceAllocationPhase<TraceAlloca
|
||||
|
||||
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) {
|
||||
|
@ -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.RegisterAllocationConfig;
|
||||
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 @@ final class TraceLinearScanResolveDataFlowPhase extends TraceLinearScanAllocatio
|
||||
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";
|
||||
|
||||
/*
|
||||
|
@ -171,7 +171,7 @@ public class CompilationResultBuilder {
|
||||
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.
|
||||
|
@ -24,7 +24,7 @@ package org.graalvm.compiler.lir.phases;
|
||||
|
||||
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 @@ public class AllocationStage extends LIRPhaseSuite<AllocationContext> {
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
@ -45,12 +45,12 @@ public class LoopPartialUnrollPhase extends LoopPhase<LoopPolicies> {
|
||||
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 @@ public class LoopPartialUnrollPhase extends LoopPhase<LoopPolicies> {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.FixedWithNextNode;
|
||||
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 @@ public abstract class LoopTransformations {
|
||||
// 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 abstract class LoopTransformations {
|
||||
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 @@ public abstract class LoopTransformations {
|
||||
|
||||
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 @@ public abstract class LoopTransformations {
|
||||
|
||||
// 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 @@ public abstract class LoopTransformations {
|
||||
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 @@ public abstract class LoopTransformations {
|
||||
}
|
||||
}
|
||||
|
||||
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 abstract class LoopTransformations {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -26,24 +26,34 @@ import org.graalvm.compiler.debug.DebugContext;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,12 @@ import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
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 class LoopPartialUnrollTest extends GraalCompilerTest {
|
||||
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 @@ public class LoopPartialUnrollTest extends GraalCompilerTest {
|
||||
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 class LoopPartialUnrollTest extends GraalCompilerTest {
|
||||
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 @@ public class LoopPartialUnrollTest extends GraalCompilerTest {
|
||||
@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 @@ public class LoopPartialUnrollTest extends GraalCompilerTest {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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.EconomicMap;
|
||||
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 @@ public class LoopEx {
|
||||
|
||||
private class InvariantPredicate implements NodePredicate {
|
||||
|
||||
private final Graph.Mark mark;
|
||||
|
||||
InvariantPredicate() {
|
||||
this.mark = loopBegin().graph().getMark();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Node n) {
|
||||
if (loopBegin().graph().isNew(mark, n)) {
|
||||
// Newly created nodes are unknown.
|
||||
return false;
|
||||
}
|
||||
return isOutsideLoop(n);
|
||||
}
|
||||
}
|
||||
|
||||
public void reassociateInvariants() {
|
||||
InvariantPredicate invariant = new InvariantPredicate();
|
||||
public boolean reassociateInvariants() {
|
||||
int count = 0;
|
||||
StructuredGraph graph = loopBegin().graph();
|
||||
InvariantPredicate invariant = new InvariantPredicate();
|
||||
for (BinaryArithmeticNode<?> binary : whole().nodes().filter(BinaryArithmeticNode.class)) {
|
||||
if (!binary.isAssociative()) {
|
||||
continue;
|
||||
}
|
||||
ValueNode result = BinaryArithmeticNode.reassociate(binary, invariant, binary.getX(), binary.getY());
|
||||
if (result != binary) {
|
||||
DebugContext debug = graph.getDebug();
|
||||
if (debug.isLogEnabled()) {
|
||||
debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result);
|
||||
}
|
||||
if (!result.isAlive()) {
|
||||
assert !result.isDeleted();
|
||||
result = graph.addOrUniqueWithInputs(result);
|
||||
}
|
||||
DebugContext debug = graph.getDebug();
|
||||
if (debug.isLogEnabled()) {
|
||||
debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result);
|
||||
}
|
||||
binary.replaceAtUsages(result);
|
||||
GraphUtil.killWithUnusedFloatingInputs(binary);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count != 0;
|
||||
}
|
||||
|
||||
public boolean detectCounted() {
|
||||
|
@ -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.CommitAllocationNode;
|
||||
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 @@ public abstract class LoopFragment {
|
||||
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 @@ public abstract class LoopFragment {
|
||||
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 ?
|
||||
|
@ -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.AbstractBeginNode;
|
||||
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 class LoopFragmentInside extends LoopFragment {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -300,6 +300,16 @@ public final class LoopBeginNode extends AbstractMergeNode implements IterableNo
|
||||
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();
|
||||
|
@ -35,7 +35,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
||||
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,11 +45,15 @@ public final class FixedValueAnchorNode extends FixedWithNextNode implements LIR
|
||||
return object;
|
||||
}
|
||||
|
||||
public FixedValueAnchorNode(ValueNode object) {
|
||||
super(TYPE, object.stamp());
|
||||
protected FixedValueAnchorNode(NodeClass<? extends FixedValueAnchorNode> c, ValueNode object) {
|
||||
super(c, object.stamp());
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public FixedValueAnchorNode(ValueNode object) {
|
||||
this(TYPE, object);
|
||||
}
|
||||
|
||||
public FixedValueAnchorNode(ValueNode object, Stamp predefinedStamp) {
|
||||
super(TYPE, predefinedStamp);
|
||||
this.object = object;
|
||||
|
@ -39,6 +39,7 @@ import org.graalvm.compiler.nodes.spi.Lowerable;
|
||||
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 @@ public final class RawStoreNode extends UnsafeAccessNode implements StateSplit,
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -1092,7 +1092,7 @@ public class InvocationPlugins {
|
||||
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);
|
||||
|
@ -90,7 +90,7 @@ public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable,
|
||||
|
||||
@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 @@ public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable,
|
||||
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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public class TestOptionKey {
|
||||
}
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,8 +47,17 @@ public class ModifiableOptionValues extends OptionValues {
|
||||
v.set(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ModifiableOptionValues extends OptionValues {
|
||||
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 @@ public class ModifiableOptionValues extends OptionValues {
|
||||
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));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public class OptionValues {
|
||||
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;
|
||||
|
@ -101,15 +101,12 @@ public class ExpandLogicPhase extends Phase {
|
||||
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;
|
||||
|
@ -35,6 +35,7 @@ import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
|
||||
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 @@ public class UseTrappingNullChecksPhase extends BasePhase<LowTierContext> {
|
||||
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());
|
||||
|
@ -86,23 +86,23 @@ public abstract class BasePhase<C> implements PhaseSizeContract {
|
||||
|
||||
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;
|
||||
|
||||
|
@ -30,7 +30,6 @@ import java.util.Arrays;
|
||||
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 @@ public final class SchedulePhase extends Phase {
|
||||
}
|
||||
|
||||
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 @@ public final class SchedulePhase extends Phase {
|
||||
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 @@ public final class SchedulePhase extends Phase {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,6 +48,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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 @@ public class GraalDebugHandlersFactory implements DebugHandlersFactory {
|
||||
}
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -31,7 +31,7 @@ public final class ReplacementsUtil {
|
||||
// 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
|
||||
|
@ -320,6 +320,7 @@ public final class MethodHandleNode extends MacroStateSplitNode implements Simpl
|
||||
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 @@ public final class MethodHandleNode extends MacroStateSplitNode implements Simpl
|
||||
}
|
||||
ValueNode valueNode = adder.add(PiNode.create(argument, StampFactory.object(targetType), guard.asNode()));
|
||||
arguments[index] = valueNode;
|
||||
} else {
|
||||
inst.safeDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ import org.graalvm.util.EconomicMap;
|
||||
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 class PEReadEliminationBlockState extends PartialEscapeBlockState<P
|
||||
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 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState<P
|
||||
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 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState<P
|
||||
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 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState<P
|
||||
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 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState<P
|
||||
} 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 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState<P
|
||||
} 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();
|
||||
|
@ -31,6 +31,7 @@ import java.util.List;
|
||||
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
state.addReadCache(unproxiedObject, identity, index, load, this);
|
||||
state.addReadCache(unproxiedObject, identity, index, kind, load, this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -177,13 +180,13 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
}
|
||||
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure<PEReadE
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,7 @@ package org.graalvm.compiler.virtual.phases.ea;
|
||||
|
||||
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 @@ public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<
|
||||
*/
|
||||
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 @@ public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<
|
||||
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];
|
||||
}
|
||||
|
@ -1009,12 +1009,7 @@ public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockStat
|
||||
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;
|
||||
}
|
||||
@ -1023,6 +1018,18 @@ public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockStat
|
||||
break;
|
||||
}
|
||||
}
|
||||
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");
|
||||
@ -1069,14 +1076,34 @@ public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockStat
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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 + "]";
|
||||
}
|
||||
}
|
@ -151,15 +151,17 @@ public final class OptionDescriptor {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user