--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java Wed Oct 11 17:11:28 2017 -0700
@@ -253,13 +253,17 @@
* Comparator for sorting blocks based on loop depth and probability.
*/
private static class BlockOrderComparator<T extends AbstractBlockBase<T>> implements Comparator<T> {
+ private static final double EPSILON = 1E-6;
@Override
public int compare(T a, T b) {
- // Loop blocks before any loop exit block.
- int diff = b.getLoopDepth() - a.getLoopDepth();
- if (diff != 0) {
- return diff;
+ // Loop blocks before any loop exit block. The only exception are blocks that are
+ // (almost) impossible to reach.
+ if (a.probability() > EPSILON && b.probability() > EPSILON) {
+ int diff = b.getLoopDepth() - a.getLoopDepth();
+ if (diff != 0) {
+ return diff;
+ }
}
// Blocks with high probability before blocks with low probability.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java Wed Oct 11 17:11:28 2017 -0700
@@ -172,7 +172,7 @@
PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -1249,7 +1249,7 @@
}
protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
- return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true));
+ return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 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;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+public class HashMapGetTest extends GraalCompilerTest {
+
+ public static void mapGet(HashMap<Integer, Integer> map, Integer key) {
+ map.get(key);
+ }
+
+ @Test
+ public void hashMapTest() {
+ HashMap<Integer, Integer> map = new HashMap<>();
+ ResolvedJavaMethod get = getResolvedJavaMethod(HashMapGetTest.class, "mapGet");
+ for (int i = 0; i < 5000; i++) {
+ mapGet(map, i);
+ map.put(i, i);
+ mapGet(map, i);
+ }
+ test(get, null, map, new Integer(0));
+ for (IfNode ifNode : lastCompiledGraph.getNodes(IfNode.TYPE)) {
+ LogicNode condition = ifNode.condition();
+ if (ifNode.getTrueSuccessorProbability() < 0.4 && condition instanceof ObjectEqualsNode) {
+ assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return.", ifNode.trueSuccessor(), ifNode.trueSuccessor().next());
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,146 @@
+/*
+ * 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;
+
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaKind;
+import sun.misc.Unsafe;
+
+/**
+ * Tests that off-heap memory writes don't prevent optimization of on-heap accesses.
+ */
+public class OffHeapUnsafeAccessTest extends GraalCompilerTest {
+
+ static final Unsafe UNSAFE = initUnsafe();
+
+ private static Unsafe initUnsafe() {
+ try {
+ // Fast path when we are trusted.
+ return Unsafe.getUnsafe();
+ } catch (SecurityException se) {
+ // Slow path when we are not trusted.
+ try {
+ Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+ theUnsafe.setAccessible(true);
+ return (Unsafe) theUnsafe.get(Unsafe.class);
+ } catch (Exception e) {
+ throw new RuntimeException("exception while trying to get Unsafe", e);
+ }
+ }
+ }
+
+ public byte unboxByteAndStore(long memory, byte[] box) {
+ byte val = box[0];
+ UNSAFE.putByte(memory, val);
+ UNSAFE.putByte(null, memory, val);
+ return box[0];
+ }
+
+ public char unboxCharAndStore(long memory, char[] box) {
+ char val = box[0];
+ UNSAFE.putChar(memory, val);
+ UNSAFE.putChar(null, memory, val);
+ return box[0];
+ }
+
+ public int unboxIntAndStore(long memory, int[] box) {
+ int val = box[0];
+ UNSAFE.putInt(memory, val);
+ UNSAFE.putInt(null, memory, val);
+ return box[0];
+ }
+
+ public long unboxLongAndStore(long memory, long[] box) {
+ long val = box[0];
+ UNSAFE.putLong(memory, val);
+ UNSAFE.putLong(null, memory, val);
+ UNSAFE.putAddress(memory, val);
+ return box[0];
+ }
+
+ public float unboxFloatAndStore(long memory, float[] box) {
+ float val = box[0];
+ UNSAFE.putFloat(memory, val);
+ UNSAFE.putFloat(null, memory, val);
+ return box[0];
+ }
+
+ public double unboxDoubleAndStore(long memory, double[] box) {
+ double val = box[0];
+ UNSAFE.putDouble(memory, val);
+ UNSAFE.putDouble(null, memory, val);
+ return box[0];
+ }
+
+ private void assertExactlyOneArrayLoad(JavaKind elementKind) {
+ int total = 0;
+ for (ReadNode read : lastCompiledGraph.getNodes().filter(ReadNode.class)) {
+ if (read.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind))) {
+ total++;
+ }
+ }
+ Assert.assertEquals(1, total);
+ }
+
+ @Test
+ public void testGet() {
+ long buf = allocBuf();
+ if (buf != 0) {
+ try {
+ test("unboxByteAndStore", buf, new byte[]{40});
+ assertExactlyOneArrayLoad(JavaKind.Byte);
+
+ test("unboxCharAndStore", buf, new char[]{41});
+ assertExactlyOneArrayLoad(JavaKind.Char);
+
+ test("unboxIntAndStore", buf, new int[]{42});
+ assertExactlyOneArrayLoad(JavaKind.Int);
+
+ test("unboxLongAndStore", buf, new long[]{43});
+ assertExactlyOneArrayLoad(JavaKind.Long);
+
+ test("unboxFloatAndStore", buf, new float[]{44.0F});
+ assertExactlyOneArrayLoad(JavaKind.Float);
+
+ test("unboxDoubleAndStore", buf, new double[]{45.0D});
+ assertExactlyOneArrayLoad(JavaKind.Double);
+ } finally {
+ UNSAFE.freeMemory(buf);
+ }
+ }
+ }
+
+ protected long allocBuf() {
+ try {
+ return UNSAFE.allocateMemory(16);
+ } catch (OutOfMemoryError e) {
+ return 0L;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class StableArrayReadFoldingTest extends GraalCompilerTest {
+
+ static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16];
+ static final int[] STABLE_INT_ARRAY = new int[16];
+
+ static final long BOOLEAN_ARRAY_BASE_OFFSET;
+ static final long INT_ARRAY_BASE_OFFSET;
+
+ static {
+ BOOLEAN_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class);
+ INT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
+ }
+
+ @Override
+ protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) {
+ StructuredGraph graph = super.parseForCompile(method, compilationId, options);
+ // Mimic @Stable array constants.
+ for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class).snapshot()) {
+ if (getConstantReflection().readArrayLength(constantNode.asJavaConstant()) != null) {
+ ConstantNode newConstantNode = graph.unique(ConstantNode.forConstant(constantNode.asJavaConstant(), 1, true, getMetaAccess()));
+ constantNode.replaceAndDelete(newConstantNode);
+ }
+ }
+ return graph;
+ }
+
+ public static boolean killWithSameType() {
+ boolean beforeKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+ STABLE_BOOLEAN_ARRAY[0] = true;
+ boolean afterKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+
+ STABLE_BOOLEAN_ARRAY[0] = false;
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testKillWithSameType() {
+ ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameType");
+ testAgainstExpected(method, new Result(true, null), null);
+ }
+
+ public static boolean killWithDifferentType() {
+ byte beforeKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+ STABLE_BOOLEAN_ARRAY[0] = true;
+ byte afterKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+
+ STABLE_BOOLEAN_ARRAY[0] = false;
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testKillWithDifferentType() {
+ ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentType");
+ testAgainstExpected(method, new Result(true, null), null);
+ }
+
+ public static boolean killWithSameTypeUnaligned() {
+ int beforeKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+ STABLE_INT_ARRAY[0] = 0x01020304;
+ int afterKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+
+ STABLE_INT_ARRAY[0] = 0;
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testKillWithSameTypeUnaligned() {
+ Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64);
+ ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameTypeUnaligned");
+ testAgainstExpected(method, new Result(true, null), null);
+ }
+
+ public static boolean killWithDifferentTypeUnaligned() {
+ byte beforeKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+ STABLE_INT_ARRAY[0] = 0x01020304;
+ byte afterKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+
+ STABLE_INT_ARRAY[0] = 0;
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testKillWithDifferentTypeUnaligned() {
+ Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64);
+ ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentTypeUnaligned");
+ testAgainstExpected(method, new Result(true, null), null);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -82,7 +82,7 @@
PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -89,7 +89,7 @@
OptionValues options = getInitialOptions();
StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options)).method(method).build();
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -46,11 +46,13 @@
public static double SideEffectD;
public static double SideEffectL;
+ private static final long booleanArrayBaseOffset;
private static final long byteArrayBaseOffset;
private static final long intArrayBaseOffset;
private static final long longArrayBaseOffset;
static {
+ booleanArrayBaseOffset = UNSAFE.arrayBaseOffset(boolean[].class);
byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class);
intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class);
longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class);
@@ -212,4 +214,77 @@
test("testWriteFloatToIntArraySnippet");
}
+ public static final byte[] FINAL_BYTE_ARRAY = new byte[16];
+
+ public static boolean alignedKill() {
+ int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+ FINAL_BYTE_ARRAY[0] = 1;
+ int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+
+ FINAL_BYTE_ARRAY[0] = 0; // reset
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testAlignedKill() {
+ test("alignedKill");
+ }
+
+ public static boolean unalignedKill() {
+ int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+ FINAL_BYTE_ARRAY[1] = 1;
+ int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+
+ FINAL_BYTE_ARRAY[1] = 0; // reset
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testUnalignedKill() {
+ test("unalignedKill");
+ }
+
+ public static final boolean[] FINAL_BOOLEAN_ARRAY = new boolean[16];
+
+ public static boolean killBooleanAccessToBooleanArrayViaBASTORE() {
+ boolean beforeKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+ FINAL_BOOLEAN_ARRAY[0] = true;
+ boolean afterKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+
+ FINAL_BOOLEAN_ARRAY[0] = false; // reset
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testKillBooleanAccessToBooleanArrayViaBASTORE() {
+ test("killBooleanAccessToBooleanArrayViaBASTORE");
+ }
+
+ public static boolean killByteAccessToBooleanArrayViaBASTORE() {
+ byte beforeKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+ FINAL_BOOLEAN_ARRAY[0] = true;
+ byte afterKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+
+ FINAL_BOOLEAN_ARRAY[0] = false; // reset
+ return beforeKill == afterKill;
+ }
+
+ @Test
+ public void testKillByteAccessToBooleanArrayViaBASTORE() {
+ test("killByteAccessToBooleanArrayViaBASTORE");
+ }
+
+ public static boolean unsafeWriteToBooleanArray() {
+ UNSAFE.putByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset, (byte) 2);
+ boolean result = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+
+ FINAL_BOOLEAN_ARRAY[0] = false; // reset
+ return result;
+ }
+
+ @Test
+ public void testUnsafeWriteToBooleanArray() {
+ test("unsafeWriteToBooleanArray");
+ }
+
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -123,7 +123,7 @@
MetaAccessProvider metaAccess = providers.getMetaAccess();
PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
OptionValues options = getInitialOptions();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -344,7 +344,7 @@
MetaAccessProvider metaAccess = providers.getMetaAccess();
PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
OptionValues options = getInitialOptions();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -268,7 +268,7 @@
MetaAccessProvider metaAccess = providers.getMetaAccess();
PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
OptionValues options = getInitialOptions();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.core.test.ea;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.junit.Test;
import sun.misc.Unsafe;
@@ -36,7 +37,7 @@
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
-public class PEAReadEliminationTest extends EarlyReadEliminationTest {
+public class PEAReadEliminationTest extends GraalCompilerTest {
public static int testIndexed1Snippet(int[] array) {
array[1] = 1;
@@ -50,7 +51,7 @@
@Test
public void testIndexed1() {
- StructuredGraph graph = processMethod("testIndexed1Snippet", false);
+ StructuredGraph graph = processMethod("testIndexed1Snippet");
assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count());
}
@@ -70,7 +71,7 @@
@Test
public void testIndexed2() {
- StructuredGraph graph = processMethod("testIndexed2Snippet", false);
+ StructuredGraph graph = processMethod("testIndexed2Snippet");
assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count());
}
@@ -94,7 +95,7 @@
@Test
public void testIndexed3() {
- StructuredGraph graph = processMethod("testIndexed3Snippet", false);
+ StructuredGraph graph = processMethod("testIndexed3Snippet");
assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
}
@@ -113,7 +114,7 @@
@Test
public void testIndexed4() {
- StructuredGraph graph = processMethod("testIndexed4Snippet", false);
+ StructuredGraph graph = processMethod("testIndexed4Snippet");
assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
}
@@ -129,7 +130,7 @@
@Test
public void testUnsafe1() {
- StructuredGraph graph = processMethod("testUnsafe1Snippet", false);
+ StructuredGraph graph = processMethod("testUnsafe1Snippet");
assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
}
@@ -142,7 +143,7 @@
@Test
public void testUnsafe2() {
- StructuredGraph graph = processMethod("testUnsafe2Snippet", false);
+ StructuredGraph graph = processMethod("testUnsafe2Snippet");
assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count());
}
@@ -158,7 +159,7 @@
@Test
public void testUnsafe3() {
- StructuredGraph graph = processMethod("testUnsafe3Snippet", false);
+ StructuredGraph graph = processMethod("testUnsafe3Snippet");
assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
}
@@ -172,28 +173,11 @@
@Test
public void testUnsafe4() {
- StructuredGraph graph = processMethod("testUnsafe4Snippet", false);
+ StructuredGraph graph = processMethod("testUnsafe4Snippet");
assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count());
}
- private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
- private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2;
-
- public static int testUnsafe5Snippet(int v, long[] array) {
- int s = UNSAFE.getInt(array, offsetLong1);
- UNSAFE.putInt(array, offsetLong1, v);
- UNSAFE.putInt(array, offsetLong2, v);
- return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2);
- }
-
- @Test
- public void testUnsafe5() {
- StructuredGraph graph = processMethod("testUnsafe5Snippet", false);
- assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
- }
-
- @Override
- protected StructuredGraph processMethod(final String snippet, boolean doLowering) {
+ protected StructuredGraph processMethod(final String snippet) {
StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
HighTierContext context = getDefaultHighTierContext();
new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017, 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.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
+import org.graalvm.compiler.nodes.extended.RawStoreNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+import org.junit.Test;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class TrufflePEATest extends GraalCompilerTest {
+
+ /**
+ * This class mimics the behavior of {@code FrameWithoutBoxing}.
+ */
+ static class Frame {
+ long[] primitiveLocals;
+
+ Frame(int size) {
+ primitiveLocals = new long[size];
+ }
+ }
+
+ /**
+ * This class mimics the behavior of {@code DynamicObjectL6I6}.
+ */
+ static class DynamicObject {
+ int primitiveField0;
+ int primitiveField1;
+ }
+
+ private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
+ private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2;
+
+ private static final long primitiveField0Offset;
+
+ static {
+ try {
+ Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0");
+ primitiveField0Offset = UNSAFE.objectFieldOffset(primitiveField0);
+ } catch (NoSuchFieldException | SecurityException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static int unsafeAccessToLongArray(int v, Frame frame) {
+ long[] array = frame.primitiveLocals;
+ int s = UNSAFE.getInt(array, offsetLong1);
+ UNSAFE.putInt(array, offsetLong1, v);
+ UNSAFE.putInt(array, offsetLong2, v);
+ return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2);
+ }
+
+ @Test
+ public void testUnsafeAccessToLongArray() {
+ StructuredGraph graph = processMethod("unsafeAccessToLongArray");
+ assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
+ }
+
+ /**
+ * The following value should be less than the default value of
+ * {@link GraalOptions#MaximumEscapeAnalysisArrayLength}.
+ */
+ private static final int FRAME_SIZE = 16;
+
+ public static long newFrame(long v) {
+ Frame frame = new Frame(FRAME_SIZE);
+ // Testing unsafe accesses with other kinds requires special handling of the initialized
+ // entry kind.
+ UNSAFE.putLong(frame.primitiveLocals, offsetLong1, v);
+ return UNSAFE.getLong(frame.primitiveLocals, offsetLong1);
+ }
+
+ @Test
+ public void testNewFrame() {
+ StructuredGraph graph = processMethod("newFrame");
+ assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count());
+ }
+
+ protected StructuredGraph processMethod(final String snippet) {
+ StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO);
+ HighTierContext context = getDefaultHighTierContext();
+ new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+ new PartialEscapePhase(true, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+ return graph;
+ }
+
+ public static double accessDynamicObject(double v) {
+ DynamicObject obj = new DynamicObject();
+ UNSAFE.putDouble(obj, primitiveField0Offset, v);
+ return UNSAFE.getDouble(obj, primitiveField0Offset);
+ }
+
+ @Test
+ public void testAccessDynamicObject() {
+ StructuredGraph graph = processMethod("accessDynamicObject");
+ assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count());
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java Wed Oct 11 17:11:28 2017 -0700
@@ -256,7 +256,7 @@
* yet and the bytecode parser would only create a graph.
*/
Plugins plugins = new Plugins(new InvocationPlugins());
- GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
/*
* For simplicity, we ignore all exception handling during the static analysis.
* This is a constraint of this example code, a real static analysis needs to
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java Wed Oct 11 17:11:28 2017 -0700
@@ -181,6 +181,12 @@
public String toString() {
StringBuilder str = new StringBuilder();
str.append(super.toString());
+ str.append(context());
+ return str.toString();
+ }
+
+ public String context() {
+ StringBuilder str = new StringBuilder();
for (String s : context) {
str.append("\n\tat ").append(s);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Wed Oct 11 17:11:28 2017 -0700
@@ -38,6 +38,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
+import java.util.function.Supplier;
import org.graalvm.compiler.core.common.Fields;
import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
@@ -598,6 +599,15 @@
}
}
+ /**
+ * Update the source position only if it is null.
+ */
+ public void updateNodeSourcePosition(Supplier<NodeSourcePosition> sourcePositionSupp) {
+ if (this.sourcePosition == null) {
+ setNodeSourcePosition(sourcePositionSupp.get());
+ }
+ }
+
public DebugCloseable withNodeSourcePosition() {
return graph.withNodeSourcePosition(this);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Wed Oct 11 17:11:28 2017 -0700
@@ -195,7 +195,7 @@
Node result = graph.getNode(nodeId);
if (result == null) {
// node was deleted -> clear the bit and continue searching
- bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex);
+ bits[wordIndex] = bits[wordIndex] & ~(1L << bitIndex);
int nextNodeId = nodeId + 1;
if ((nextNodeId & (Long.SIZE - 1)) == 0) {
// we reached the end of this word
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Oct 11 17:11:28 2017 -0700
@@ -28,6 +28,10 @@
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
import java.util.ArrayList;
import java.util.List;
@@ -39,6 +43,7 @@
import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
import org.graalvm.compiler.debug.DebugContext;
@@ -415,49 +420,49 @@
return result;
}
- @Override
- public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
- ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL);
- Constant[] constants = new Constant[]{constant};
- AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
- Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
- append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
- AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
- return emitMove(result);
- }
-
- @Override
- public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
- ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL);
- Constant[] constants = new Constant[]{constant};
- AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
- Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
+ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+ ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
return emitMove(result);
}
+ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+ Constant[] constants = new Constant[]{constant};
+ Object[] notes = new Object[]{action};
+ return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
+ }
+
+ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
+ AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+ return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
+ }
+
@Override
- public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
- ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS);
- Constant[] constants = new Constant[]{method};
- AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
- Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS};
- append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
- AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
- return emitMove(result);
+ public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+ return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+ }
+ @Override
+ public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+ return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
}
@Override
public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
- ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL);
- Constant[] constants = new Constant[]{constant};
- AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
- Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE};
- append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
- AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
- return emitMove(result);
+ return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
+ }
+
+ @Override
+ public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
+ AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
+ return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
+ }
+
+ @Override
+ public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
+ AllocatableValue[] constantDescriptions = new AllocatableValue[0];
+ return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Oct 11 17:11:28 2017 -0700
@@ -27,6 +27,7 @@
import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
@@ -255,7 +256,7 @@
@Override
public void emitPrefetchAllocate(Value address) {
SPARCAddressValue addr = asAddressValue(address);
- append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr));
+ append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads));
}
public StackSlot getDeoptimizationRescueSlot() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java Wed Oct 11 17:11:28 2017 -0700
@@ -52,8 +52,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -475,6 +477,7 @@
private void compile(String classPath) throws IOException {
final String[] entries = classPath.split(File.pathSeparator);
long start = System.currentTimeMillis();
+ Map<Thread, StackTraceElement[]> initialThreads = Thread.getAllStackTraces();
try {
// compile dummy method to get compiler initialized outside of the
@@ -549,7 +552,13 @@
classFileCounter++;
- if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) {
+ if (className.startsWith("jdk.management.") ||
+ className.startsWith("jdk.internal.cmm.*") ||
+ // GR-5881: The class initializer for
+ // sun.tools.jconsole.OutputViewer
+ // spawns non-daemon threads for redirecting sysout and syserr.
+ // These threads tend to cause deadlock at VM exit
+ className.startsWith("sun.tools.jconsole.")) {
continue;
}
@@ -643,6 +652,33 @@
} else {
TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get());
}
+
+ // Apart from the main thread, there should be only be daemon threads
+ // alive now. If not, then a class initializer has probably started
+ // a thread that could cause a deadlock while trying to exit the VM.
+ // One known example of this is sun.tools.jconsole.OutputViewer which
+ // spawns threads to redirect sysout and syserr. To help debug such
+ // scenarios, the stacks of potentially problematic threads are dumped.
+ Map<Thread, StackTraceElement[]> suspiciousThreads = new HashMap<>();
+ for (Map.Entry<Thread, StackTraceElement[]> e : Thread.getAllStackTraces().entrySet()) {
+ Thread thread = e.getKey();
+ if (thread != Thread.currentThread() && !initialThreads.containsKey(thread) && !thread.isDaemon() && thread.isAlive()) {
+ suspiciousThreads.put(thread, e.getValue());
+ }
+ }
+ if (!suspiciousThreads.isEmpty()) {
+ TTY.println("--- Non-daemon threads started during CTW ---");
+ for (Map.Entry<Thread, StackTraceElement[]> e : suspiciousThreads.entrySet()) {
+ Thread thread = e.getKey();
+ if (thread.isAlive()) {
+ TTY.println(thread.toString() + " " + thread.getState());
+ for (StackTraceElement ste : e.getValue()) {
+ TTY.println("\tat " + ste);
+ }
+ }
+ }
+ TTY.println("---------------------------------------------");
+ }
}
private synchronized void startThreads() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,145 @@
+/*
+ * 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.hotspot.test;
+
+import java.util.function.IntPredicate;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import java.security.PrivilegedAction;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
+import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HotSpotInvokeDynamicPluginTest extends HotSpotGraalCompilerTest {
+ @Override
+ protected Plugins getDefaultGraphBuilderPlugins() {
+ Plugins plugins = super.getDefaultGraphBuilderPlugins();
+ plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
+ plugins.setInvokeDynamicPlugin(new HotSpotInvokeDynamicPlugin() {
+ @Override
+ public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+ // Allow invokedynamic testing with older JVMCI
+ ResolvedJavaMethod m = builder.getMethod();
+ if (m.getName().startsWith("invokeDynamic") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) {
+ return false;
+ }
+ return super.isResolvedDynamicInvoke(builder, index, opcode);
+ }
+
+ @Override
+ public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+ // Allow invokehandle testing with older JVMCI
+ ResolvedJavaMethod m = builder.getMethod();
+ if (m.getName().startsWith("invokeHandle") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) {
+ return true;
+ }
+ return super.supportsDynamicInvoke(builder, index, opcode);
+ }
+ });
+ return plugins;
+ }
+
+ @Override
+ protected InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+ return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+ }
+
+ private void test(String name, int expectedResolves, int expectedStubCalls) {
+ StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true));
+ MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+
+ CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+ Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveDynamicConstantNode.class).count());
+ Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicStubCall.class).count());
+ PhaseContext context = new PhaseContext(getProviders());
+ new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+ new GuardLoweringPhase().apply(graph, midTierContext);
+ new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+ new FrameStateAssignmentPhase().apply(graph);
+ new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, context);
+ Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicConstantNode.class).count());
+ Assert.assertEquals(expectedStubCalls, graph.getNodes().filter(ResolveDynamicStubCall.class).count());
+ }
+
+ public static IntPredicate invokeDynamic1() {
+ IntPredicate i = (v) -> v > 1;
+ return i;
+ }
+
+ public static PrivilegedAction<Integer> invokeDynamic2(String s) {
+ return s::length;
+ }
+
+ static final MethodHandle objToStringMH;
+
+ static {
+ MethodHandle mh = null;
+ try {
+ mh = MethodHandles.lookup().findVirtual(Object.class, "toString", MethodType.methodType(String.class));
+ } catch (Exception e) {
+ }
+ objToStringMH = mh;
+ }
+
+ // invokehandle
+ public static String invokeHandle1(Object o) throws Throwable {
+ return (String) objToStringMH.invokeExact(o);
+ }
+
+ @Test
+ public void test1() {
+ test("invokeDynamic1", 1, 1);
+ }
+
+ @Test
+ public void test2() {
+ test("invokeDynamic2", 1, 1);
+ }
+
+ @Test
+ public void test3() {
+ test("invokeHandle1", 1, 1);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,153 @@
+/*
+ * 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.hotspot.test;
+
+import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
+import org.junit.Assert;
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+/**
+ * Tests that a hs_err crash log contains expected content.
+ */
+public class HsErrLogTest extends GraalCompilerTest {
+
+ @Test
+ public void test1() throws IOException, InterruptedException {
+ List<String> args = new ArrayList<>();
+ if (Java8OrEarlier) {
+ args.add("-XX:-UseJVMCIClassLoader");
+ }
+ args.add("-XX:+UseJVMCICompiler");
+ args.add("-XX:CompileOnly=" + Crasher.class.getName() + "::tryCrash");
+ args.add(Crasher.class.getName());
+ testHelper(args);
+ }
+
+ private static final boolean VERBOSE = Boolean.getBoolean(HsErrLogTest.class.getSimpleName() + ".verbose");
+
+ private static void testHelper(List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
+ List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+ vmArgs.removeIf(a -> a.startsWith("-Dgraal."));
+ vmArgs.remove("-esa");
+ vmArgs.remove("-ea");
+ vmArgs.addAll(extraVmArgs);
+
+ Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs);
+ if (VERBOSE) {
+ System.out.println(proc);
+ }
+
+ Pattern re = Pattern.compile("# +(.*hs_err_pid[\\d]+\\.log)");
+
+ for (String line : proc.output) {
+ Matcher m = re.matcher(line);
+ if (m.matches()) {
+ File path = new File(m.group(1));
+ Assert.assertTrue(path.toString(), path.exists());
+ checkHsErr(path);
+ return;
+ }
+ }
+
+ Assert.fail("Could not find " + re.pattern());
+ }
+
+ private static void checkHsErr(File hsErrPath) {
+ try (BufferedReader br = new BufferedReader(new FileReader(hsErrPath))) {
+ String line = br.readLine();
+ String sig = Crasher.class.getName() + ".tryCrash(JI)I";
+ List<String> lines = new ArrayList<>();
+ while (line != null) {
+ if (line.contains(sig)) {
+ if (!VERBOSE) {
+ hsErrPath.delete();
+ }
+ return;
+ }
+ lines.add(line);
+ line = br.readLine();
+ }
+ throw new AssertionError("Could not find line containing \"" + sig + "\" in " + hsErrPath +
+ ":" + System.lineSeparator() + String.join(System.lineSeparator(), lines));
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+}
+
+class Crasher {
+ public static void main(String[] args) {
+ int iter = 0;
+ long mem = UNSAFE.allocateMemory(1000);
+ while (iter < Integer.MAX_VALUE) {
+ tryCrash(mem, iter);
+ iter++;
+ }
+ }
+
+ protected static int tryCrash(long mem, int iter) {
+ if (GraalDirectives.inCompiledCode()) {
+ UNSAFE.putInt(0, iter);
+ return 0;
+ } else {
+ UNSAFE.putInt(mem, iter);
+ return UNSAFE.getInt(mem);
+ }
+ }
+
+ static final Unsafe UNSAFE = initUnsafe();
+
+ private static Unsafe initUnsafe() {
+ try {
+ // Fast path when we are trusted.
+ return Unsafe.getUnsafe();
+ } catch (SecurityException se) {
+ // Slow path when we are not trusted.
+ try {
+ Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+ theUnsafe.setAccessible(true);
+ return (Unsafe) theUnsafe.get(Unsafe.class);
+ } catch (Exception e) {
+ throw new RuntimeException("exception while trying to get Unsafe", e);
+ }
+ }
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Wed Oct 11 17:11:28 2017 -0700
@@ -240,7 +240,7 @@
}
/**
- * @return the compilation id plus a trailing '%' is the compilation is an OSR to match
+ * @return the compilation id plus a trailing '%' if the compilation is an OSR to match
* PrintCompilation style output
*/
public String getIdString() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Wed Oct 11 17:11:28 2017 -0700
@@ -29,7 +29,6 @@
import java.util.List;
import java.util.stream.Collectors;
-import org.graalvm.compiler.debug.Assertions;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
@@ -73,7 +72,6 @@
protected CompilerConfigurationFactory(String name, int autoSelectionPriority) {
this.name = name;
this.autoSelectionPriority = autoSelectionPriority;
- assert checkAndAddNewFactory(this);
}
public abstract CompilerConfiguration createCompilerConfiguration();
@@ -127,18 +125,18 @@
}
/**
- * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all
- * {@link CompilerConfigurationFactory} instances.
+ * Asserts uniqueness of {@link #name} and {@link #autoSelectionPriority} for {@code factory} in
+ * {@code factories}.
*/
- private static final List<CompilerConfigurationFactory> factories = Assertions.assertionsEnabled() ? new ArrayList<>() : null;
-
- private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) {
+ private static boolean checkUnique(CompilerConfigurationFactory factory, List<CompilerConfigurationFactory> factories) {
for (CompilerConfigurationFactory other : factories) {
- assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name;
- assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() +
- ": " + factory.autoSelectionPriority;
+ if (other != factory) {
+ assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name;
+ assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " +
+ other.getClass().getName() +
+ ": " + factory.autoSelectionPriority;
+ }
}
- factories.add(factory);
return true;
}
@@ -148,6 +146,7 @@
private static List<CompilerConfigurationFactory> getAllCandidates() {
List<CompilerConfigurationFactory> candidates = new ArrayList<>();
for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) {
+ assert checkUnique(candidate, candidates);
candidates.add(candidate);
}
Collections.sort(candidates);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -35,6 +35,7 @@
}
public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol");
+ public final long resolveDynamicInvoke = getAddress("CompilerRuntime::resolve_dynamic_invoke");
public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol");
public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters");
public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -297,6 +297,11 @@
/**
* @see ResolveConstantStubCall
*/
+ public static final ForeignCallDescriptor RESOLVE_DYNAMIC_INVOKE = new ForeignCallDescriptor("resolve_dynamic_invoke", Object.class, Word.class);
+
+ /**
+ * @see ResolveConstantStubCall
+ */
public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class);
/**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -68,7 +68,7 @@
* @return value of loaded address in register
*/
default Value emitLoadObjectAddress(Constant constant) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to load an object address is not currently supported on %s", target().arch);
}
/**
@@ -79,7 +79,7 @@
* @return Value of loaded address in register
*/
default Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to load a metaspace address is not currently supported on %s", target().arch);
}
/**
@@ -90,7 +90,7 @@
* @return value of loaded global in register
*/
default Value emitLoadConfigValue(int markId, LIRKind kind) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to load a config value is not currently supported on %s", target().arch);
}
/**
@@ -100,10 +100,21 @@
* @param constantDescription a description of the string that need to be materialized (and
* interned) as java.lang.String, generated with {@link EncodedSymbolConstant}
* @param frameState frame state for the runtime call
- * @return Returns the address of the requested constant.
+ * @return the address of the requested constant.
*/
default Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to resolve an object constant is not currently supported on %s", target().arch);
+ }
+
+ /**
+ * Emits code to resolve a dynamic constant.
+ *
+ * @param constant original constant
+ * @param frameState frame state for the runtime call
+ * @return the address of the requested constant.
+ */
+ default Value emitResolveDynamicInvoke(Constant constant, LIRFrameState frameState) {
+ throw new GraalError("Emitting code to resolve a dynamic constant is not currently supported on %s", target().arch);
}
/**
@@ -113,10 +124,10 @@
* @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant}
* generated by {@link EncodedSymbolConstant}
* @param frameState frame state for the runtime call
- * @return Returns the address of the requested constant.
+ * @return the address of the requested constant.
*/
default Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to resolve a metaspace constant is not currently supported on %s", target().arch);
}
/**
@@ -129,10 +140,10 @@
* @param methodDescription is symbolic description of the constant generated by
* {@link EncodedSymbolConstant}
* @param frameState frame state for the runtime call
- * @return Returns the address of the requested constant.
+ * @return the address of the requested constant.
*/
default Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to resolve a method and load counters is not currently supported on %s", target().arch);
}
/**
@@ -144,10 +155,10 @@
* @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant}
* generated by {@link EncodedSymbolConstant}
* @param frameState frame state for the runtime call
- * @return Returns the address of the requested constant.
+ * @return the address of the requested constant.
*/
default Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to initialize a class is not currently supported on %s", target().arch);
}
/**
@@ -156,7 +167,7 @@
* @return value of the counter
*/
default Value emitRandomSeed() {
- throw GraalError.unimplemented();
+ throw new GraalError("Emitting code to return a random seed is not currently supported on %s", target().arch);
}
/**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,7 +24,6 @@
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs;
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs;
import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
@@ -70,6 +69,7 @@
import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp;
@@ -214,10 +214,8 @@
arraycopySnippets = new ArrayCopySnippets.Templates(options, factories, runtime, providers, target);
stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target);
hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target);
- if (GeneratePIC.getValue(options)) {
- resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
- profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
- }
+ resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
+ profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(options, factories, providers, target));
}
@@ -364,6 +362,10 @@
}
} else if (n instanceof IdentityHashCodeNode) {
hashCodeSnippets.lower((IdentityHashCodeNode) n, tool);
+ } else if (n instanceof ResolveDynamicConstantNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool);
+ }
} else if (n instanceof ResolveConstantNode) {
if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,8 +22,6 @@
*/
package org.graalvm.compiler.hotspot.meta;
-import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
-import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
@@ -63,7 +61,6 @@
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.DynamicPiNode;
import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.LogicNode;
@@ -80,7 +77,6 @@
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
-import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
@@ -101,13 +97,9 @@
import org.graalvm.word.LocationIdentity;
import jdk.vm.ci.code.CodeUtil;
-import jdk.vm.ci.hotspot.HotSpotObjectConstant;
-import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
-import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -139,42 +131,9 @@
plugins.appendTypePlugin(nodePlugin);
plugins.appendNodePlugin(nodePlugin);
OptionValues options = replacements.getOptions();
- if (GeneratePIC.getValue(options)) {
- // AOT needs to filter out bad invokes
- plugins.prependNodePlugin(new NodePlugin() {
- @Override
- public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
- if (b.parsingIntrinsic()) {
- return false;
- }
- // check if the holder has a valid fingerprint
- if (((HotSpotResolvedObjectType) method.getDeclaringClass()).getFingerprint() == 0) {
- // Deopt otherwise
- b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
- return true;
- }
- // the last argument that may come from appendix, check if it is a supported
- // constant type
- if (args.length > 0) {
- JavaConstant constant = args[args.length - 1].asJavaConstant();
- if (constant != null && constant instanceof HotSpotObjectConstant) {
- HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType();
- Class<?> clazz = type.mirror();
- if (clazz.equals(String.class)) {
- return false;
- }
- if (Class.class.isAssignableFrom(clazz) && ((HotSpotResolvedObjectType) type).getFingerprint() != 0) {
- return false;
- }
- b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
- return true;
- }
- }
- return false;
- }
- });
+ if (!GeneratePIC.getValue(options)) {
+ plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
}
- plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
plugins.appendInlineInvokePlugin(replacements);
if (InlineDuringParsing.getValue(options)) {
plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
@@ -196,7 +155,9 @@
registerClassPlugins(plugins, config, replacementBytecodeProvider);
registerSystemPlugins(invocationPlugins, foreignCalls);
registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
- registerCallSitePlugins(invocationPlugins);
+ if (!GeneratePIC.getValue(options)) {
+ registerCallSitePlugins(invocationPlugins);
+ }
registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -44,6 +44,7 @@
import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY;
import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE;
import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
@@ -305,6 +306,7 @@
registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore());
linkForeignCall(options, providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+ linkForeignCall(options, providers, RESOLVE_DYNAMIC_INVOKE, cr.resolveDynamicInvoke, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
linkForeignCall(options, providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
linkForeignCall(options, providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
linkForeignCall(options, providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,156 @@
+/*
+ * 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.hotspot.meta;
+
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class HotSpotInvokeDynamicPlugin implements InvokeDynamicPlugin {
+
+ private static final Class<? extends ConstantPool> hscp;
+ private static final MethodHandle isResolvedDynamicInvokeMH;
+
+ static {
+ MethodHandle m = null;
+ Class<? extends ConstantPool> c = null;
+ try {
+ c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class);
+ m = MethodHandles.lookup().findVirtual(c, "isResolvedDynamicInvoke", MethodType.methodType(boolean.class, int.class, int.class));
+ } catch (Exception e) {
+ }
+ isResolvedDynamicInvokeMH = m;
+ hscp = c;
+ }
+
+ private static boolean isResolvedDynamicInvoke(ConstantPool constantPool, int index, int opcode) {
+ if (isResolvedDynamicInvokeMH != null) {
+ if (!hscp.isInstance(constantPool)) {
+ return false;
+ }
+ try {
+ return (boolean) isResolvedDynamicInvokeMH.invoke(constantPool, index, opcode);
+ } catch (Throwable t) {
+ throw GraalError.shouldNotReachHere(t);
+ }
+ }
+ throw GraalError.shouldNotReachHere("isResolvedDynamicInvokeMH not set");
+ }
+
+ private final DynamicTypeStore dynoStore;
+ private final boolean treatAppendixAsConstant;
+
+ public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore, boolean treatAppendixAsConstant) {
+ this.dynoStore = dynoStore;
+ this.treatAppendixAsConstant = treatAppendixAsConstant;
+ }
+
+ public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore) {
+ this(dynoStore, true);
+ }
+
+ public HotSpotInvokeDynamicPlugin() {
+ this(null);
+ }
+
+ // invokehandle support
+ @Override
+ public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+ ConstantPool constantPool = builder.getCode().getConstantPool();
+ if (isResolvedDynamicInvokeMH == null) {
+ // If older JVMCI, but HotSpotInvokeDynamicPlugin is being
+ // used for testing, return true so that we continue along the
+ // plugin path.
+ return true;
+ }
+ return isResolvedDynamicInvoke(constantPool, index, opcode);
+ }
+
+ @Override
+ public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+ return opcode == Bytecodes.INVOKEDYNAMIC || isResolvedDynamicInvokeMH != null;
+ }
+
+ public DynamicTypeStore getDynamicTypeStore() {
+ return dynoStore;
+ }
+
+ @Override
+ public void recordDynamicMethod(GraphBuilderContext builder, int index, int opcode, ResolvedJavaMethod target) {
+ assert supportsDynamicInvoke(builder, index, opcode);
+ HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod();
+ HotSpotResolvedObjectType methodHolder = method.getDeclaringClass();
+
+ HotSpotResolvedJavaMethod adapter = (HotSpotResolvedJavaMethod) target;
+ if (dynoStore != null) {
+ dynoStore.recordAdapter(opcode, methodHolder, index, adapter);
+ }
+ }
+
+ @Override
+ public ValueNode genAppendixNode(GraphBuilderContext builder, int index, int opcode, JavaConstant appendixConstant, FrameState frameState) {
+ JavaConstant appendix = appendixConstant;
+ assert supportsDynamicInvoke(builder, index, opcode);
+ HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod();
+ HotSpotResolvedObjectType methodHolder = method.getDeclaringClass();
+
+ if (dynoStore != null) {
+ appendix = dynoStore.recordAppendix(opcode, methodHolder, index, appendix);
+ }
+
+ ConstantNode appendixNode = ConstantNode.forConstant(appendix, builder.getMetaAccess(), builder.getGraph());
+
+ Stamp appendixStamp = appendixNode.stamp();
+ Stamp resolveStamp = treatAppendixAsConstant ? appendixStamp : appendixStamp.unrestricted();
+ ResolveDynamicConstantNode resolveNode = new ResolveDynamicConstantNode(resolveStamp, appendixNode);
+ ResolveDynamicConstantNode added = builder.append(resolveNode);
+ assert added == resolveNode;
+ added.setStateBefore(frameState);
+ return resolveNode;
+ }
+
+ public interface DynamicTypeStore {
+
+ void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int cpi, HotSpotResolvedJavaMethod adapter);
+
+ JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int cpi, JavaConstant appendix);
+
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,68 @@
+/*
+ * 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.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
+
+import org.graalvm.word.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
+public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single {
+ public static final NodeClass<ResolveDynamicConstantNode> TYPE = NodeClass.create(ResolveDynamicConstantNode.class);
+
+ @Input ValueNode value;
+
+ public ResolveDynamicConstantNode(Stamp valueStamp, ValueNode value) {
+ super(TYPE, valueStamp);
+ this.value = value;
+ }
+
+ public ValueNode value() {
+ return value;
+ }
+
+ @Override
+ public void lower(LoweringTool tool) {
+ tool.getLowerer().lower(this, tool);
+ }
+
+ @Override
+ public boolean canDeoptimize() {
+ return true;
+ }
+
+ @Override
+ public LocationIdentity getLocationIdentity() {
+ return LocationIdentity.any();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,113 @@
+/*
+ * 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.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
+
+import org.graalvm.compiler.debug.GraalError;
+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.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.word.LocationIdentity;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the VM via a regular stub.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16)
+public class ResolveDynamicStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single {
+ public static final NodeClass<ResolveDynamicStubCall> TYPE = NodeClass.create(ResolveDynamicStubCall.class);
+
+ @OptionalInput protected ValueNode value;
+ @OptionalInput(InputType.State) protected FrameState stateBefore;
+ protected Constant constant;
+
+ public ResolveDynamicStubCall(ValueNode value) {
+ super(TYPE, value.stamp());
+ this.value = value;
+ }
+
+ @NodeIntrinsic
+ public static native Object resolveInvoke(Object value);
+
+ @Override
+ public Node canonical(CanonicalizerTool tool) {
+ if (value != null) {
+ constant = GraphUtil.foldIfConstantAndRemove(this, value);
+ }
+ return this;
+ }
+
+ @Override
+ public void generate(NodeLIRBuilderTool gen) {
+ assert constant != null : "Expected the value to fold: " + value;
+ Value result;
+ LIRFrameState fs = gen.state(this);
+ assert fs != null : "The stateAfter is null";
+ result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveDynamicInvoke(constant, fs);
+ gen.setResult(this, result);
+ }
+
+ @Override
+ public boolean canDeoptimize() {
+ return true;
+ }
+
+ @Override
+ public LocationIdentity getLocationIdentity() {
+ return LocationIdentity.any();
+ }
+
+ @Override
+ public FrameState stateBefore() {
+ return stateBefore;
+ }
+
+ @Override
+ public void setStateBefore(FrameState f) {
+ updateUsages(stateBefore, f);
+ stateBefore = f;
+ }
+
+ @Override
+ public void markDeleted() {
+ throw GraalError.shouldNotReachHere("ResolveDynamicStubCall node deleted");
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java Wed Oct 11 17:11:28 2017 -0700
@@ -42,6 +42,7 @@
import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -107,6 +108,7 @@
// @formatter:off
return n instanceof LoadConstantIndirectlyNode ||
n instanceof LoadConstantIndirectlyFixedNode ||
+ n instanceof ResolveDynamicConstantNode ||
n instanceof ResolveConstantNode ||
n instanceof InitializeKlassNode;
// @formatter:on
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -36,7 +36,9 @@
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall;
import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall;
@@ -73,6 +75,15 @@
}
@Snippet
+ public static Object resolveDynamicConstant(Object constant) {
+ Object result = LoadConstantIndirectlyNode.loadObject(constant);
+ if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) {
+ result = ResolveDynamicStubCall.resolveInvoke(constant);
+ }
+ return result;
+ }
+
+ @Snippet
public static KlassPointer resolveKlassConstant(KlassPointer constant) {
KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant);
if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) {
@@ -110,6 +121,7 @@
public static class Templates extends AbstractTemplates {
private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant");
+ private final SnippetInfo resolveDynamicConstant = snippet(ResolveConstantSnippets.class, "resolveDynamicConstant");
private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant");
private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters");
private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass");
@@ -119,6 +131,25 @@
super(options, factories, providers, providers.getSnippetReflection(), target);
}
+ public void lower(ResolveDynamicConstantNode resolveConstantNode, LoweringTool tool) {
+ StructuredGraph graph = resolveConstantNode.graph();
+
+ ValueNode value = resolveConstantNode.value();
+ assert value.isConstant() : "Expected a constant: " + value;
+ SnippetInfo snippet = resolveDynamicConstant;
+
+ Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+ args.add("constant", value);
+
+ SnippetTemplate template = template(graph.getDebug(), args);
+ template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
+
+ assert resolveConstantNode.hasNoUsages();
+ if (!resolveConstantNode.isDeleted()) {
+ GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode);
+ }
+ }
+
public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) {
StructuredGraph graph = resolveConstantNode.graph();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -374,6 +374,7 @@
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.InvokeDynamicPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -933,8 +934,13 @@
* @param type the unresolved type of the constant
*/
protected void handleUnresolvedLoadConstant(JavaType type) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ /*
+ * Track source position for deopt nodes even if
+ * GraphBuilderConfiguration.trackNodeSourcePosition is not set.
+ */
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
@@ -942,7 +948,7 @@
* @param object the object value whose type is being checked against {@code type}
*/
protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
- assert !graphBuilderConfig.eagerResolving();
+ assert !graphBuilderConfig.unresolvedIsError();
append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile));
frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER));
}
@@ -952,9 +958,10 @@
* @param object the object value whose type is being checked against {@code type}
*/
protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
- assert !graphBuilderConfig.eagerResolving();
+ assert !graphBuilderConfig.unresolvedIsError();
AbstractBeginNode successor = graph.add(new BeginNode());
DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1));
lastInstr = successor;
frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0));
@@ -964,8 +971,9 @@
* @param type the type being instantiated
*/
protected void handleUnresolvedNewInstance(JavaType type) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
@@ -973,8 +981,9 @@
* @param length the length of the array
*/
protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
@@ -982,8 +991,9 @@
* @param dims the dimensions for the multi-array
*/
protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
@@ -991,8 +1001,9 @@
* @param receiver the object containing the field or {@code null} if {@code field} is static
*/
protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
@@ -1001,16 +1012,18 @@
* @param receiver the object containing the field or {@code null} if {@code field} is static
*/
protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
* @param type
*/
protected void handleUnresolvedExceptionType(JavaType type) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
/**
@@ -1018,8 +1031,9 @@
* @param invokeKind
*/
protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) {
- assert !graphBuilderConfig.eagerResolving();
- append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ assert !graphBuilderConfig.unresolvedIsError();
+ DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) {
@@ -1307,7 +1321,12 @@
return false;
}
- protected void genInvokeStatic(JavaMethod target) {
+ protected void genInvokeStatic(int cpi, int opcode) {
+ JavaMethod target = lookupMethod(cpi, opcode);
+ genInvokeStatic(target);
+ }
+
+ void genInvokeStatic(JavaMethod target) {
if (callTargetIsResolved(target)) {
ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
ResolvedJavaType holder = resolvedTarget.getDeclaringClass();
@@ -1332,6 +1351,11 @@
}
}
+ protected void genInvokeInterface(int cpi, int opcode) {
+ JavaMethod target = lookupMethod(cpi, opcode);
+ genInvokeInterface(target);
+ }
+
protected void genInvokeInterface(JavaMethod target) {
if (callTargetIsResolved(target)) {
ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
@@ -1341,44 +1365,108 @@
}
}
- protected void genInvokeDynamic(JavaMethod target) {
- if (target instanceof ResolvedJavaMethod) {
- JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC);
- if (appendix != null) {
- frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
- }
- ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false));
- appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
- } else {
+ protected void genInvokeDynamic(int cpi, int opcode) {
+ JavaMethod target = lookupMethod(cpi, opcode);
+ genInvokeDynamic(target);
+ }
+
+ void genInvokeDynamic(JavaMethod target) {
+ if (!(target instanceof ResolvedJavaMethod) || !genDynamicInvokeHelper((ResolvedJavaMethod) target, stream.readCPI4(), INVOKEDYNAMIC)) {
handleUnresolvedInvoke(target, InvokeKind.Static);
}
}
- protected void genInvokeVirtual(JavaMethod target) {
- if (callTargetIsResolved(target)) {
- /*
- * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...)
- * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see
- * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic
- */
- boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic();
- JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL);
- if (appendix != null) {
- frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
+ protected void genInvokeVirtual(int cpi, int opcode) {
+ JavaMethod target = lookupMethod(cpi, opcode);
+ genInvokeVirtual(target);
+ }
+
+ private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) {
+ assert opcode == INVOKEDYNAMIC || opcode == INVOKEVIRTUAL;
+
+ InvokeDynamicPlugin invokeDynamicPlugin = graphBuilderConfig.getPlugins().getInvokeDynamicPlugin();
+
+ if (opcode == INVOKEVIRTUAL && invokeDynamicPlugin != null && !invokeDynamicPlugin.isResolvedDynamicInvoke(this, cpi, opcode)) {
+ // regular invokevirtual, let caller handle it
+ return false;
+ }
+
+ if (GeneratePIC.getValue(options) && (invokeDynamicPlugin == null || !invokeDynamicPlugin.supportsDynamicInvoke(this, cpi, opcode))) {
+ // bail out if static compiler and no dynamic type support
+ append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ return true;
+ }
+
+ JavaConstant appendix = constantPool.lookupAppendix(cpi, opcode);
+ ValueNode appendixNode = null;
+
+ if (appendix != null) {
+ if (invokeDynamicPlugin != null) {
+ invokeDynamicPlugin.recordDynamicMethod(this, cpi, opcode, target);
+
+ // Will perform runtime type checks and static initialization
+ FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+ appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore);
+ } else {
+ appendixNode = ConstantNode.forConstant(appendix, metaAccess, graph);
}
- ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
- if (hasReceiver) {
- appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
- } else {
- appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
- }
+
+ frameState.push(JavaKind.Object, appendixNode);
+
+ } else if (GeneratePIC.getValue(options)) {
+ // Need to emit runtime guard and perform static initialization.
+ // Not implemented yet.
+ append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+ return true;
+ }
+
+ boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic();
+ ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
+ if (hasReceiver) {
+ appendInvoke(InvokeKind.Virtual, target, args);
} else {
+ appendInvoke(InvokeKind.Static, target, args);
+ }
+
+ return true;
+ }
+
+ void genInvokeVirtual(JavaMethod target) {
+ if (!genInvokeVirtualHelper(target)) {
handleUnresolvedInvoke(target, InvokeKind.Virtual);
}
-
- }
-
- protected void genInvokeSpecial(JavaMethod target) {
+ }
+
+ private boolean genInvokeVirtualHelper(JavaMethod target) {
+ if (!callTargetIsResolved(target)) {
+ return false;
+ }
+
+ ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
+ int cpi = stream.readCPI();
+
+ /*
+ * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or
+ * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see
+ * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic
+ */
+
+ if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) {
+ return true;
+ }
+
+ ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
+ appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
+
+ return true;
+ }
+
+ protected void genInvokeSpecial(int cpi, int opcode) {
+ JavaMethod target = lookupMethod(cpi, opcode);
+ genInvokeSpecial(target);
+ }
+
+ void genInvokeSpecial(JavaMethod target) {
if (callTargetIsResolved(target)) {
assert target != null;
assert target.getSignature() != null;
@@ -2149,9 +2237,9 @@
TTY.println(s);
}
- protected BytecodeParserError asParserError(Throwable e) {
+ protected RuntimeException throwParserError(Throwable e) {
if (e instanceof BytecodeParserError) {
- return (BytecodeParserError) e;
+ throw (BytecodeParserError) e;
}
BytecodeParser bp = this;
BytecodeParserError res = new BytecodeParserError(e);
@@ -2159,7 +2247,7 @@
res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci()));
bp = bp.parent;
}
- return res;
+ throw res;
}
protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
@@ -2837,7 +2925,7 @@
// Don't wrap bailouts as parser errors
throw e;
} catch (Throwable e) {
- throw asParserError(e);
+ throw throwParserError(e);
}
if (lastInstr == null || lastInstr.next() != null) {
@@ -3257,7 +3345,7 @@
int nextBC = stream.readUByte(nextBCI);
if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) {
stream.next();
- genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value);
+ genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
} else {
frameState.push(JavaKind.Object, value);
}
@@ -3506,15 +3594,18 @@
return result;
}
- private JavaField lookupField(int cpi, int opcode) {
+ protected JavaField lookupField(int cpi, int opcode) {
maybeEagerlyResolve(cpi, opcode);
JavaField result = constantPool.lookupField(cpi, method, opcode);
+
if (graphBuilderConfig.eagerResolving()) {
- assert result instanceof ResolvedJavaField : "Not resolved: " + result;
- ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
- if (!declaringClass.isInitialized()) {
- assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
- declaringClass.initialize();
+ assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
+ if (result instanceof ResolvedJavaField) {
+ ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
+ if (!declaringClass.isInitialized()) {
+ assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
+ declaringClass.initialize();
+ }
}
}
assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
@@ -3524,11 +3615,11 @@
private Object lookupConstant(int cpi, int opcode) {
maybeEagerlyResolve(cpi, opcode);
Object result = constantPool.lookupConstant(cpi);
- assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
+ assert !graphBuilderConfig.unresolvedIsError() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
return result;
}
- private void maybeEagerlyResolve(int cpi, int bytecode) {
+ protected void maybeEagerlyResolve(int cpi, int bytecode) {
if (intrinsicContext != null) {
constantPool.loadReferencedType(cpi, bytecode);
} else if (graphBuilderConfig.eagerResolving()) {
@@ -3653,9 +3744,12 @@
}
}
- void genNewInstance(int cpi) {
+ protected void genNewInstance(int cpi) {
JavaType type = lookupType(cpi, NEW);
-
+ genNewInstance(type);
+ }
+
+ void genNewInstance(JavaType type) {
if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) {
handleUnresolvedNewInstance(type);
return;
@@ -3790,8 +3884,13 @@
frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims)));
}
- private void genGetField(JavaField field) {
- genGetField(field, frameState.pop(JavaKind.Object));
+ protected void genGetField(int cpi, int opcode) {
+ genGetField(cpi, opcode, frameState.pop(JavaKind.Object));
+ }
+
+ protected void genGetField(int cpi, int opcode, ValueNode receiverInput) {
+ JavaField field = lookupField(cpi, opcode);
+ genGetField(field, receiverInput);
}
private void genGetField(JavaField field, ValueNode receiverInput) {
@@ -3867,7 +3966,12 @@
return false;
}
- private void genPutField(JavaField field) {
+ protected void genPutField(int cpi, int opcode) {
+ JavaField field = lookupField(cpi, opcode);
+ genPutField(field);
+ }
+
+ protected void genPutField(JavaField field) {
genPutField(field, frameState.pop(field.getJavaKind()));
}
@@ -3895,6 +3999,11 @@
}
}
+ protected void genGetStatic(int cpi, int opcode) {
+ JavaField field = lookupField(cpi, opcode);
+ genGetStatic(field);
+ }
+
private void genGetStatic(JavaField field) {
ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null);
if (resolvedField == null) {
@@ -3956,7 +4065,12 @@
return null;
}
- private void genPutStatic(JavaField field) {
+ protected void genPutStatic(int cpi, int opcode) {
+ JavaField field = lookupField(cpi, opcode);
+ genPutStatic(field);
+ }
+
+ protected void genPutStatic(JavaField field) {
ValueNode value = frameState.pop(field.getJavaKind());
ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value);
if (resolvedField == null) {
@@ -4320,15 +4434,15 @@
case DRETURN : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break;
case ARETURN : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break;
case RETURN : genReturn(null, JavaKind.Void); break;
- case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
- case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
- case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
- case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
- case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
- case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
- case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
- case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
- case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
+ case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, opcode); break;
+ case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, opcode); break;
+ case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, opcode); break;
+ case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, opcode); break;
+ case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(cpi, opcode); break;
+ case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(cpi, opcode); break;
+ case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(cpi, opcode); break;
+ case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(cpi, opcode); break;
+ case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(cpi, opcode); break;
case NEW : genNewInstance(stream.readCPI()); break;
case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break;
case ANEWARRAY : genNewObjectArray(stream.readCPI()); break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,69 @@
+/*
+ * 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.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_irem4 extends JTTTest {
+
+ public static int test(int a) {
+ return a % 8;
+ }
+
+ @Test
+ public void run0() throws Throwable {
+ runTest("test", -1);
+ }
+
+ @Test
+ public void run1() throws Throwable {
+ runTest("test", -2);
+ }
+
+ @Test
+ public void run2() throws Throwable {
+ runTest("test", -8);
+ }
+
+ @Test
+ public void run3() throws Throwable {
+ runTest("test", 16);
+ }
+
+ @Test
+ public void run4() throws Throwable {
+ runTest("test", -16);
+ }
+
+ @Test
+ public void run5() throws Throwable {
+ runTest("test", -23);
+ }
+
+ @Test
+ public void run6() throws Throwable {
+ runTest("test", 23);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java Wed Oct 11 17:11:28 2017 -0700
@@ -34,18 +34,17 @@
public static final LIRInstructionClass<SPARCPrefetchOp> TYPE = LIRInstructionClass.create(SPARCPrefetchOp.class);
public static final SizeEstimate SIZE = SizeEstimate.create(1);
- private final int instr; // AllocatePrefetchInstr
+ private final SPARCAssembler.Fcn fcn;
@Alive({COMPOSITE}) protected SPARCAddressValue address;
- public SPARCPrefetchOp(SPARCAddressValue address, int instr) {
+ public SPARCPrefetchOp(SPARCAddressValue address, SPARCAssembler.Fcn fcn) {
super(TYPE, SIZE);
this.address = address;
- this.instr = instr;
+ this.fcn = fcn;
}
@Override
public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
- assert instr >= 0 && instr < SPARCAssembler.Fcn.values().length : instr;
- masm.prefetch(address.toAddress(), SPARCAssembler.Fcn.values()[instr]);
+ masm.prefetch(address.toAddress(), fcn);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Wed Oct 11 17:11:28 2017 -0700
@@ -466,28 +466,6 @@
AbstractMergeNode merge = (AbstractMergeNode) node;
EndNode singleEnd = merge.forwardEndAt(0);
- /*
- * In some corner cases, the MergeNode already has PhiNodes. Since there is a single
- * EndNode, each PhiNode can only have one input, and we can replace the PhiNode with
- * this single input.
- */
- for (PhiNode phi : merge.phis()) {
- assert phi.inputs().count() == 1 : "input count must match end count";
- Node singlePhiInput = phi.inputs().first();
-
- /*
- * We do not have the orderID of the PhiNode anymore, so we need to search through
- * the complete list of nodes to find a match.
- */
- for (int i = 0; i < loopScope.createdNodes.length; i++) {
- if (loopScope.createdNodes[i] == phi) {
- loopScope.createdNodes[i] = singlePhiInput;
- }
- }
-
- phi.replaceAndDelete(singlePhiInput);
- }
-
/* Nodes that would use this merge as the guard need to use the previous block. */
registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
@@ -973,8 +951,22 @@
int phiNodeOrderId = readOrderId(methodScope);
ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId);
+ ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId);
- ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId);
+ if (existing != null && merge.phiPredecessorCount() == 1) {
+ /*
+ * When exploding loops and the code after the loop (FULL_EXPLODE_UNTIL_RETURN),
+ * then an existing value can already be registered: Parsing of the code before the
+ * loop registers it when preparing for the later merge. The code after the loop,
+ * which starts with a clone of the values that were created before the loop, sees
+ * the stale value when processing the merge the first time. We can safely ignore
+ * the stale value because it will never be needed to be merged (we are exploding
+ * until we hit a return).
+ */
+ assert methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN && phiNodeScope.loopIteration > 0;
+ existing = null;
+ }
+
if (lazyPhi && (existing == null || existing == phiInput)) {
/* Phi function not yet necessary. */
registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Wed Oct 11 17:11:28 2017 -0700
@@ -30,6 +30,8 @@
import java.util.Iterator;
import java.util.List;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
@@ -52,7 +54,10 @@
import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
import org.graalvm.compiler.nodes.calc.IsNullNode;
import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.nodes.util.GraphUtil;
@@ -256,6 +261,123 @@
}
}
}
+
+ if (tryEliminateBoxedReferenceEquals(tool)) {
+ return;
+ }
+ }
+
+ private boolean isUnboxedFrom(MetaAccessProvider meta, ValueNode x, ValueNode src) {
+ if (x == src) {
+ return true;
+ } else if (x instanceof UnboxNode) {
+ return isUnboxedFrom(meta, ((UnboxNode) x).getValue(), src);
+ } else if (x instanceof PiNode) {
+ PiNode pi = (PiNode) x;
+ return isUnboxedFrom(meta, pi.getOriginalNode(), src);
+ } else if (x instanceof LoadFieldNode) {
+ LoadFieldNode load = (LoadFieldNode) x;
+ ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
+ if (load.getValue().stamp().javaType(meta).equals(integerType)) {
+ return isUnboxedFrom(meta, load.getValue(), src);
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Attempts to replace the following pattern:
+ *
+ * <pre>
+ * Integer x = ...;
+ * Integer y = ...;
+ * if ((x == y) || x.equals(y)) { ... }
+ * </pre>
+ *
+ * with:
+ *
+ * <pre>
+ * Integer x = ...;
+ * Integer y = ...;
+ * if (x.equals(y)) { ... }
+ * </pre>
+ *
+ * whenever the probability that the reference check will pass is relatively small.
+ *
+ * See GR-1315 for more information.
+ */
+ private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) {
+ if (!(condition instanceof ObjectEqualsNode)) {
+ return false;
+ }
+
+ MetaAccessProvider meta = tool.getMetaAccess();
+ ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition;
+ ValueNode x = equalsCondition.getX();
+ ValueNode y = equalsCondition.getY();
+ ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
+
+ // At least one argument for reference equal must be a boxed primitive.
+ if (!x.stamp().javaType(meta).equals(integerType) && !y.stamp().javaType(meta).equals(integerType)) {
+ return false;
+ }
+
+ // The reference equality check is usually more efficient compared to a boxing check.
+ // The success of the reference equals must therefore be relatively rare, otherwise it makes
+ // no sense to eliminate it.
+ if (getTrueSuccessorProbability() > 0.4) {
+ return false;
+ }
+
+ // True branch must be empty.
+ if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) {
+ if (trueSuccessor.next() instanceof EndNode) {
+ // Empty true branch.
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ // False branch must only check the unboxed values.
+ UnboxNode unbox = null;
+ FixedGuardNode unboxCheck = null;
+ for (FixedNode node : falseSuccessor.getBlockNodes()) {
+ if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode ||
+ node instanceof LoadFieldNode || node instanceof LoopExitNode)) {
+ return false;
+ }
+ if (node instanceof UnboxNode) {
+ if (unbox == null) {
+ unbox = (UnboxNode) node;
+ } else {
+ return false;
+ }
+ }
+ if (!(node instanceof FixedGuardNode)) {
+ continue;
+ }
+ FixedGuardNode fixed = (FixedGuardNode) node;
+ if (!(fixed.condition() instanceof IntegerEqualsNode)) {
+ continue;
+ }
+ IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition();
+ if ((isUnboxedFrom(meta, equals.getX(), x) && isUnboxedFrom(meta, equals.getY(), y)) || (isUnboxedFrom(meta, equals.getX(), y) && isUnboxedFrom(meta, equals.getY(), x))) {
+ unboxCheck = fixed;
+ }
+ }
+ if (unbox == null || unboxCheck == null) {
+ return false;
+ }
+
+ // Falsify the reference check.
+ setCondition(graph().addOrUnique(LogicConstantNode.contradiction()));
+
+ return true;
}
/**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java Wed Oct 11 17:11:28 2017 -0700
@@ -60,6 +60,11 @@
*/
public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
+ /**
+ * Denotes an off-heap address.
+ */
+ public static final LocationIdentity OFF_HEAP_LOCATION = NamedLocationIdentity.mutable("OFF_HEAP_LOCATION");
+
private final String name;
private final boolean immutable;
@@ -81,7 +86,7 @@
/**
* Creates a named unique location identity for read operations against immutable memory.
- * Immutable memory will never have a visible write in the graph, which is more restictive than
+ * Immutable memory will never have a visible write in the graph, which is more restrictive than
* Java final.
*
* @param name the name of the new location identity
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java Wed Oct 11 17:11:28 2017 -0700
@@ -60,12 +60,26 @@
return this; // this will trap, can not canonicalize
}
return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() % y);
- } else if (forY.isConstant()) {
- long c = forY.asJavaConstant().asLong();
- if (c == 1 || c == -1) {
+ } else if (forY.isConstant() && forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+ long constY = forY.asJavaConstant().asLong();
+ IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+ IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+ if (constY < 0 && constY != CodeUtil.minValue(yStamp.getBits())) {
+ return new SignedRemNode(forX, ConstantNode.forIntegerStamp(yStamp, -constY)).canonical(tool);
+ }
+
+ if (constY == 1) {
return ConstantNode.forIntegerStamp(stamp(), 0);
- } else if (c > 0 && CodeUtil.isPowerOf2(c) && forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
- return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1));
+ } else if (CodeUtil.isPowerOf2(constY)) {
+ if (xStamp.isPositive()) {
+ return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1));
+ } else if (xStamp.isNegative()) {
+ return new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1)));
+ } else {
+ return new ConditionalNode(IntegerLessThanNode.create(forX, ConstantNode.forIntegerStamp(forX.stamp(), 0)),
+ new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))),
+ new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1)));
+ }
}
}
return this;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Wed Oct 11 17:11:28 2017 -0700
@@ -30,7 +30,10 @@
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.ReinterpretNode;
import org.graalvm.compiler.nodes.java.LoadFieldNode;
@@ -38,19 +41,23 @@
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;
import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
/**
* Load of a value from a location specified as an offset relative to an object. No null check is
* performed before the load.
*/
@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
-public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable {
+public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable {
public static final NodeClass<RawLoadNode> TYPE = NodeClass.create(RawLoadNode.class);
/**
@@ -123,6 +130,32 @@
}
@Override
+ public Node canonical(CanonicalizerTool tool) {
+ if (!isAnyLocationForced() && getLocationIdentity().isAny()) {
+ ValueNode targetObject = object();
+ if (offset().isConstant() && targetObject.isConstant() && !targetObject.isNullConstant()) {
+ ConstantNode objectConstant = (ConstantNode) targetObject;
+ ResolvedJavaType type = StampTool.typeOrNull(objectConstant);
+ if (type != null && type.isArray()) {
+ JavaConstant arrayConstant = objectConstant.asJavaConstant();
+ if (arrayConstant != null) {
+ int stableDimension = objectConstant.getStableDimension();
+ if (stableDimension > 0) {
+ long constantOffset = offset().asJavaConstant().asLong();
+ Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), arrayConstant, constantOffset);
+ boolean isDefaultStable = objectConstant.isDefaultStable();
+ if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) {
+ return ConstantNode.forConstant(stamp(), constant, stableDimension - 1, isDefaultStable, tool.getMetaAccess());
+ }
+ }
+ }
+ }
+ }
+ }
+ return super.canonical(tool);
+ }
+
+ @Override
protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field) {
return LoadFieldNode.create(assumptions, object(), field);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -39,6 +39,7 @@
private InlineInvokePlugin[] inlineInvokePlugins;
private LoopExplosionPlugin loopExplosionPlugin;
private ClassInitializationPlugin classInitializationPlugin;
+ private InvokeDynamicPlugin invokeDynamicPlugin;
private ProfilingPlugin profilingPlugin;
/**
@@ -54,6 +55,7 @@
this.inlineInvokePlugins = copyFrom.inlineInvokePlugins;
this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
this.classInitializationPlugin = copyFrom.classInitializationPlugin;
+ this.invokeDynamicPlugin = copyFrom.invokeDynamicPlugin;
this.profilingPlugin = copyFrom.profilingPlugin;
}
@@ -167,6 +169,14 @@
this.classInitializationPlugin = plugin;
}
+ public InvokeDynamicPlugin getInvokeDynamicPlugin() {
+ return invokeDynamicPlugin;
+ }
+
+ public void setInvokeDynamicPlugin(InvokeDynamicPlugin plugin) {
+ this.invokeDynamicPlugin = plugin;
+ }
+
public ProfilingPlugin getProfilingPlugin() {
return profilingPlugin;
}
@@ -189,6 +199,7 @@
private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
private final boolean eagerResolving;
+ private final boolean unresolvedIsError;
private final BytecodeExceptionMode bytecodeExceptionMode;
private final boolean omitAssertions;
private final ResolvedJavaType[] skippedExceptionTypes;
@@ -216,10 +227,11 @@
Profile
}
- protected GraphBuilderConfiguration(boolean eagerResolving, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
+ protected GraphBuilderConfiguration(boolean eagerResolving, boolean unresolvedIsError, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes,
Plugins plugins) {
this.eagerResolving = eagerResolving;
+ this.unresolvedIsError = unresolvedIsError;
this.bytecodeExceptionMode = bytecodeExceptionMode;
this.omitAssertions = omitAssertions;
this.insertFullInfopoints = insertFullInfopoints;
@@ -235,35 +247,52 @@
*/
public GraphBuilderConfiguration copy() {
Plugins newPlugins = new Plugins(plugins);
- GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
- newPlugins);
+ GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition,
+ skippedExceptionTypes, newPlugins);
return result;
}
+ /**
+ * Set the {@link #unresolvedIsError} flag. This flag can be set independently from
+ * {@link #eagerResolving}, i.e., even if eager resolving fails execution is assumed to be
+ * valid. This allows us for example to process unresolved types/methods/fields even when
+ * eagerly resolving elements.
+ */
+ public GraphBuilderConfiguration withUnresolvedIsError(boolean newUnresolvedIsError) {
+ return new GraphBuilderConfiguration(eagerResolving, newUnresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+ plugins);
+ }
+
public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
- return new GraphBuilderConfiguration(newEagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
+ return new GraphBuilderConfiguration(newEagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+ plugins);
}
public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
- return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins);
+ return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes,
+ plugins);
}
public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) {
- return new GraphBuilderConfiguration(eagerResolving, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
+ return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+ plugins);
}
public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
- return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
+ return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+ plugins);
}
public GraphBuilderConfiguration withFullInfopoints(boolean newInsertFullInfopoints) {
ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
- return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins);
+ return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes,
+ plugins);
}
public GraphBuilderConfiguration withNodeSourcePosition(boolean newTrackNodeSourcePosition) {
ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
- return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, plugins);
+ return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes,
+ plugins);
}
public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -291,20 +320,16 @@
}
public static GraphBuilderConfiguration getDefault(Plugins plugins) {
- return new GraphBuilderConfiguration(false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins);
+ return new GraphBuilderConfiguration(false, false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins);
}
public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
- return new GraphBuilderConfiguration(true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins);
+ return new GraphBuilderConfiguration(true, true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins);
}
- /**
- * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
- * default is the same result as returned by {@link #eagerResolving()}. However, it may be
- * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
- */
+ /** Returns {@code true} if it is an error for a class/field/method resolution to fail. */
public boolean unresolvedIsError() {
- return eagerResolving;
+ return unresolvedIsError;
}
public Plugins getPlugins() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java Wed Oct 11 17:11:28 2017 -0700
@@ -295,4 +295,20 @@
default void notifyReplacedCall(ResolvedJavaMethod targetMethod, ConstantNode node) {
}
+
+ /**
+ * Interface whose instances hold inlining information about the current context, in a wider
+ * sense. The wider sense in this case concerns graph building approaches that don't necessarily
+ * keep a chain of {@link GraphBuilderContext} instances normally available through
+ * {@linkplain #getParent()}. Examples of such approaches are partial evaluation and incremental
+ * inlining.
+ */
+ interface ExternalInliningContext {
+ int getInlinedDepth();
+ }
+
+ default ExternalInliningContext getExternalInliningContext() {
+ return null;
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,82 @@
+/*
+ * 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.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * {@link GraphBuilderPlugin} interface for static compilation mode, allowing references to dynamic
+ * types.
+ */
+public interface InvokeDynamicPlugin extends GraphBuilderPlugin {
+
+ /**
+ * Checks for a resolved dynamic adapter method at the specified index, resulting from either a
+ * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method
+ * (HotSpot invokehandle).
+ *
+ * @param builder context for the invoke
+ * @param cpi the constant pool index
+ * @param opcode the opcode of the instruction for which the lookup is being performed
+ * @return {@code true} if a signature polymorphic method reference was found, otherwise
+ * {@code false}
+ */
+ boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode);
+
+ /**
+ * Checks if this plugin instance supports the specified dynamic invoke.
+ *
+ * @param builder context for the invoke
+ * @param cpi the constant pool index
+ * @param opcode the opcode of the invoke instruction
+ * @return {@code true} if this dynamic invoke is supported
+ */
+ boolean supportsDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode);
+
+ /**
+ * Notifies this object of the value and context of the dynamic method target (e.g., A HotSpot
+ * adapter method) for a resolved dynamic invoke.
+ *
+ * @param builder context for the invoke
+ * @param cpi the constant pool index
+ * @param opcode the opcode of the instruction for which the lookup is being performed
+ * @param target dynamic target method to record
+ */
+ void recordDynamicMethod(GraphBuilderContext builder, int cpi, int opcode, ResolvedJavaMethod target);
+
+ /**
+ * Notifies this object of the value and context of the dynamic appendix object for a resolved
+ * dynamic invoke.
+ *
+ * @param builder context for the invoke
+ * @param cpi the constant pool index
+ * @param opcode the opcode of the instruction for which the lookup is being performed
+ * @return {@link ValueNode} for appendix constant
+ */
+ ValueNode genAppendixNode(GraphBuilderContext builder, int cpi, int opcode, JavaConstant appendix, FrameState frameState);
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Wed Oct 11 17:11:28 2017 -0700
@@ -137,8 +137,9 @@
}
long offset;
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) {
- // On big endian, we do just get expect the type be right aligned in this memory slot
- offset = constantOffset - (componentType.getJavaKind().getByteCount() - Math.min(componentType.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()));
+ // On big endian, we expect the value to be correctly aligned in memory
+ int componentByteCount = componentType.getJavaKind().getByteCount();
+ offset = constantOffset - (componentByteCount - Math.min(componentByteCount, 4 + expectedEntryKind.getByteCount()));
} else {
offset = constantOffset;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java Wed Oct 11 17:11:28 2017 -0700
@@ -132,11 +132,11 @@
StructuredGraph targetGraph = null;
DebugContext debug = getDebugContext();
try (DebugContext.Scope scope = debug.scope("GraphPETest", testMethod)) {
- GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true);
+ GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true);
registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build();
CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES,
- null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null);
+ null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null);
decoder.decode(testMethod);
debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java Wed Oct 11 17:11:28 2017 -0700
@@ -63,9 +63,9 @@
public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
ParameterPlugin parameterPlugin,
- NodePlugin[] nodePlugins) {
+ NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) {
super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin,
- invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins);
+ invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod);
this.providers = providers;
this.graphBuilderConfig = graphBuilderConfig;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Wed Oct 11 17:11:28 2017 -0700
@@ -238,11 +238,11 @@
if (frameStateBuilder != null) {
if (invoke.getStackKind() != JavaKind.Void) {
- frameStateBuilder.push(returnType.getJavaKind(), invoke);
+ frameStateBuilder.push(invoke.getStackKind(), invoke);
}
invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
if (invoke.getStackKind() != JavaKind.Void) {
- frameStateBuilder.pop(returnType.getJavaKind());
+ frameStateBuilder.pop(invoke.getStackKind());
}
}
return invoke;
@@ -475,11 +475,11 @@
invoke.setNext(noExceptionEdge);
if (frameStateBuilder != null) {
if (invoke.getStackKind() != JavaKind.Void) {
- frameStateBuilder.push(returnType.getJavaKind(), invoke);
+ frameStateBuilder.push(invoke.getStackKind(), invoke);
}
invoke.setStateAfter(frameStateBuilder.create(invokeBci, invoke));
if (invoke.getStackKind() != JavaKind.Void) {
- frameStateBuilder.pop(returnType.getJavaKind());
+ frameStateBuilder.pop(invoke.getStackKind());
}
}
lastFixedNode = null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Wed Oct 11 17:11:28 2017 -0700
@@ -193,6 +193,24 @@
protected final PEMethodScope methodScope;
protected final Invoke invoke;
+ @Override
+ public ExternalInliningContext getExternalInliningContext() {
+ return new ExternalInliningContext() {
+ @Override
+ public int getInlinedDepth() {
+ int count = 0;
+ PEGraphDecoder.PEMethodScope scope = methodScope;
+ while (scope != null) {
+ if (scope.method.equals(callInlinedMethod)) {
+ count++;
+ }
+ scope = scope.caller;
+ }
+ return count;
+ }
+ };
+ }
+
public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
this.methodScope = methodScope;
this.invoke = invoke;
@@ -420,11 +438,12 @@
private final NodePlugin[] nodePlugins;
private final EconomicMap<SpecialCallTargetCacheKey, Object> specialCallTargetCache;
private final EconomicMap<ResolvedJavaMethod, Object> invocationPluginCache;
+ private final ResolvedJavaMethod callInlinedMethod;
public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
StampProvider stampProvider, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
ParameterPlugin parameterPlugin,
- NodePlugin[] nodePlugins) {
+ NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) {
super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true);
this.loopExplosionPlugin = loopExplosionPlugin;
this.invocationPlugins = invocationPlugins;
@@ -433,6 +452,7 @@
this.nodePlugins = nodePlugins;
this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT);
this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT);
+ this.callInlinedMethod = callInlinedMethod;
}
protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Wed Oct 11 17:11:28 2017 -0700
@@ -224,16 +224,12 @@
}
/**
- * Times instantiations of all templates derived form this snippet.
- *
- * @see SnippetTemplate#instantiationTimer
+ * Times instantiations of all templates derived from this snippet.
*/
private final TimerKey instantiationTimer;
/**
* Counts instantiations of all templates derived from this snippet.
- *
- * @see SnippetTemplate#instantiationCounter
*/
private final CounterKey instantiationCounter;
@@ -706,8 +702,6 @@
Object[] constantArgs = getConstantArgs(args);
StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs);
- instantiationTimer = DebugContext.timer("SnippetTemplateInstantiationTime[%#s]", args);
- instantiationCounter = DebugContext.counter("SnippetTemplateInstantiationCount[%#s]", args);
ResolvedJavaMethod method = snippetGraph.method();
Signature signature = method.getSignature();
@@ -1078,20 +1072,6 @@
private final ArrayList<Node> nodes;
/**
- * Times instantiations of this template.
- *
- * @see SnippetInfo#instantiationTimer
- */
- private final TimerKey instantiationTimer;
-
- /**
- * Counts instantiations of this template.
- *
- * @see SnippetInfo#instantiationCounter
- */
- private final CounterKey instantiationCounter;
-
- /**
* Gets the instantiation-time bindings to this template's parameters.
*
* @return the map that will be used to bind arguments to parameters when inlining this template
@@ -1406,9 +1386,8 @@
public UnmodifiableEconomicMap<Node, Node> instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) {
DebugContext debug = replacee.getDebug();
assert assertSnippetKills(replacee);
- try (DebugCloseable a = args.info.instantiationTimer.start(debug); DebugCloseable b = instantiationTimer.start(debug)) {
+ try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
args.info.instantiationCounter.increment(debug);
- instantiationCounter.increment(debug);
// Inline the snippet nodes, replacing parameters with the given args in the process
StartNode entryPointNode = snippet.start();
FixedNode firstCFGNode = entryPointNode.next();
@@ -1561,7 +1540,6 @@
assert assertSnippetKills(replacee);
try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
args.info.instantiationCounter.increment(debug);
- instantiationCounter.increment(debug);
// Inline the snippet nodes, replacing parameters with the given args in the process
StartNode entryPointNode = snippet.start();
@@ -1614,7 +1592,6 @@
assert assertSnippetKills(replacee);
try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
args.info.instantiationCounter.increment(debug);
- instantiationCounter.increment(debug);
// Inline the snippet nodes, replacing parameters with the given args in the process
StartNode entryPointNode = snippet.start();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Wed Oct 11 17:11:28 2017 -0700
@@ -30,6 +30,7 @@
import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION;
import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
import java.lang.reflect.Array;
@@ -650,7 +651,7 @@
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
// Emits a null-check for the otherwise unused receiver
unsafe.get();
- b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, LocationIdentity.any()));
+ b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, OFF_HEAP_LOCATION));
b.getGraph().markUnsafeAccess();
return true;
}
@@ -662,7 +663,8 @@
if (isVolatile) {
b.add(new MembarNode(JMM_PRE_VOLATILE_READ));
}
- b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, LocationIdentity.any()));
+ LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any();
+ b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, locationIdentity));
if (isVolatile) {
b.add(new MembarNode(JMM_POST_VOLATILE_READ));
}
@@ -685,7 +687,7 @@
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) {
// Emits a null-check for the otherwise unused receiver
unsafe.get();
- b.add(new UnsafeMemoryStoreNode(address, value, kind, LocationIdentity.any()));
+ b.add(new UnsafeMemoryStoreNode(address, value, kind, OFF_HEAP_LOCATION));
b.getGraph().markUnsafeAccess();
return true;
}
@@ -697,7 +699,8 @@
if (isVolatile) {
b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
}
- b.add(new RawStoreNode(object, offset, value, kind, LocationIdentity.any()));
+ LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any();
+ b.add(new RawStoreNode(object, offset, value, kind, locationIdentity));
if (isVolatile) {
b.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java Wed Oct 11 17:11:28 2017 -0700
@@ -25,6 +25,8 @@
import java.util.Iterator;
import java.util.List;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.nodes.FieldLocationIdentity;
import org.graalvm.compiler.nodes.ValueNode;
@@ -49,11 +51,15 @@
public final int index;
public final JavaKind kind;
- ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind) {
+ /* This flag does not affect hashCode or equals implementations. */
+ public final boolean overflowAccess;
+
+ ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind, boolean overflowAccess) {
this.identity = identity;
this.object = object;
this.index = index;
this.kind = kind;
+ this.overflowAccess = overflowAccess;
}
@Override
@@ -94,12 +100,38 @@
return super.toString() + " " + readCache;
}
+ private static JavaKind stampToJavaKind(Stamp stamp) {
+ if (stamp instanceof IntegerStamp) {
+ switch (((IntegerStamp) stamp).getBits()) {
+ case 1:
+ return JavaKind.Boolean;
+ case 8:
+ return JavaKind.Byte;
+ case 16:
+ return ((IntegerStamp) stamp).isPositive() ? JavaKind.Char : JavaKind.Short;
+ case 32:
+ return JavaKind.Int;
+ case 64:
+ return JavaKind.Long;
+ default:
+ throw new IllegalArgumentException("unexpected IntegerStamp " + stamp);
+ }
+ } else {
+ return stamp.getStackKind();
+ }
+ }
+
@Override
protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
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, instance.field(i).getJavaKind()), values.get(i));
+ JavaKind declaredKind = instance.field(i).getJavaKind();
+ if (declaredKind == stampToJavaKind(values.get(i).stamp())) {
+ // We won't cache unaligned field writes upon instantiation unless we add
+ // support for non-array objects in PEReadEliminationClosure.processUnsafeLoad.
+ readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, declaredKind, false), values.get(i));
+ }
}
}
}
@@ -112,7 +144,7 @@
return super.equivalentTo(other);
}
- public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PartialEscapeClosure<?> closure) {
+ public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, ValueNode value, PartialEscapeClosure<?> closure) {
ValueNode cacheObject;
ObjectState obj = closure.getObjectState(this, object);
if (obj != null) {
@@ -121,7 +153,7 @@
} else {
cacheObject = object;
}
- readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind), value);
+ readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind, overflowAccess), value);
}
public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure<?> closure) {
@@ -133,7 +165,7 @@
} else {
cacheObject = object;
}
- ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind));
+ ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind, false));
obj = closure.getObjectState(this, cacheValue);
if (obj != null) {
assert !obj.isVirtual();
@@ -153,7 +185,7 @@
Iterator<ReadCacheEntry> iter = readCache.getKeys().iterator();
while (iter.hasNext()) {
ReadCacheEntry entry = iter.next();
- if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) {
+ if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index || entry.overflowAccess)) {
iter.remove();
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Wed Oct 11 17:11:28 2017 -0700
@@ -31,7 +31,6 @@
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;
@@ -131,9 +130,10 @@
return false;
}
- private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) {
+ private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind accessKind, boolean overflowAccess, ValueNode value,
+ PEReadEliminationBlockState state, GraphEffectList effects) {
ValueNode unproxiedObject = GraphUtil.unproxify(object);
- ValueNode cachedValue = state.getReadCache(object, identity, index, kind, this);
+ ValueNode cachedValue = state.getReadCache(object, identity, index, accessKind, this);
ValueNode finalValue = getScalarAlias(value);
boolean result = false;
@@ -142,7 +142,7 @@
result = true;
}
state.killReadCache(identity, index);
- state.addReadCache(unproxiedObject, identity, index, kind, finalValue, this);
+ state.addReadCache(unproxiedObject, identity, index, accessKind, overflowAccess, finalValue, this);
return result;
}
@@ -150,43 +150,52 @@
ValueNode unproxiedObject = GraphUtil.unproxify(object);
ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, kind, this);
if (cachedValue != null) {
- 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.
- */
- assert load.stamp().getStackKind() == JavaKind.Int && (cachedValue.stamp().getStackKind() == JavaKind.Long || cachedValue.getStackKind() == JavaKind.Double ||
- cachedValue.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one slot fields.";
- return false;
- } else {
- // perform the read elimination
- effects.replaceAtUsages(load, cachedValue, load);
- addScalarAlias(load, cachedValue);
- return true;
- }
+ // perform the read elimination
+ effects.replaceAtUsages(load, cachedValue, load);
+ addScalarAlias(load, cachedValue);
+ return true;
} else {
- state.addReadCache(unproxiedObject, identity, index, kind, load, this);
+ state.addReadCache(unproxiedObject, identity, index, kind, false, load, this);
return false;
}
}
+ private static boolean isOverflowAccess(JavaKind accessKind, JavaKind declaredKind) {
+ if (accessKind == declaredKind) {
+ return false;
+ }
+ if (accessKind == JavaKind.Object) {
+ switch (declaredKind) {
+ case Object:
+ case Double:
+ case Long:
+ return false;
+ default:
+ return true;
+ }
+ }
+ assert accessKind.isPrimitive() : "Illegal access kind";
+ return declaredKind.isPrimitive() ? accessKind.getBitCount() > declaredKind.getBitCount() : true;
+ }
+
private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
if (load.offset().isConstant()) {
ResolvedJavaType type = StampTool.typeOrNull(load.object());
if (type != null && type.isArray()) {
+ JavaKind accessKind = load.accessKind();
+ JavaKind componentKind = type.getComponentType().getJavaKind();
long offset = load.offset().asJavaConstant().asLong();
- int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
+ int index = VirtualArrayNode.entryIndexForOffset(offset, 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, load.accessKind(), this);
- if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
+ LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
+ ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this);
+ assert cachedValue == null || load.stamp().isCompatible(cachedValue.stamp()) : "The RawLoadNode's stamp is not compatible with the cached value.";
+ if (cachedValue != null) {
effects.replaceAtUsages(load, cachedValue, load);
addScalarAlias(load, cachedValue);
return true;
} else {
- state.addReadCache(object, location, index, load.accessKind(), load, this);
+ state.addReadCache(object, location, index, accessKind, isOverflowAccess(accessKind, componentKind), load, this);
}
}
}
@@ -196,11 +205,14 @@
private boolean processUnsafeStore(RawStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
ResolvedJavaType type = StampTool.typeOrNull(store.object());
if (type != null && type.isArray()) {
- LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
+ JavaKind accessKind = store.accessKind();
+ JavaKind componentKind = type.getComponentType().getJavaKind();
+ LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
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.accessKind(), store.value(), state, effects);
+ boolean overflowAccess = isOverflowAccess(accessKind, componentKind);
+ int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
+ return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects);
} else {
processIdentity(state, location);
}
@@ -219,7 +231,8 @@
state.killReadCache();
return false;
}
- return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.field().getJavaKind(), store.value(), state, effects);
+ JavaKind kind = store.field().getJavaKind();
+ return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, kind, false, store.value(), state, effects);
}
private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
@@ -230,11 +243,32 @@
return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, load.field().getJavaKind(), state, effects);
}
+ private static JavaKind getElementKindFromStamp(ValueNode array) {
+ ResolvedJavaType type = StampTool.typeOrNull(array);
+ if (type != null && type.isArray()) {
+ return type.getComponentType().getJavaKind();
+ } else {
+ // It is likely an OSRLocal without valid stamp
+ return JavaKind.Illegal;
+ }
+ }
+
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.elementKind(), store.value(), state, effects);
+ int index = store.index().isConstant() ? ((JavaConstant) store.index().asConstant()).asInt() : -1;
+ // BASTORE (with elementKind being Byte) can be used to store values in boolean arrays.
+ JavaKind elementKind = store.elementKind();
+ if (elementKind == JavaKind.Byte) {
+ elementKind = getElementKindFromStamp(store.array());
+ if (elementKind == JavaKind.Illegal) {
+ // Could not determine the actual access kind from stamp. Hence kill both.
+ state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Boolean), index);
+ state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Byte), index);
+ return false;
+ }
+ }
+ LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind);
+ if (index != -1) {
+ return processStore(store, store.array(), arrayLocation, index, elementKind, false, store.value(), state, effects);
} else {
state.killReadCache(arrayLocation, -1);
}
@@ -244,8 +278,17 @@
private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
if (load.index().isConstant()) {
int index = ((JavaConstant) load.index().asConstant()).asInt();
- LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind());
- return processLoad(load, load.array(), arrayLocation, index, load.elementKind(), state, effects);
+ // BALOAD (with elementKind being Byte) can be used to retrieve values from boolean
+ // arrays.
+ JavaKind elementKind = load.elementKind();
+ if (elementKind == JavaKind.Byte) {
+ elementKind = getElementKindFromStamp(load.array());
+ if (elementKind == JavaKind.Illegal) {
+ return false;
+ }
+ }
+ LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind);
+ return processLoad(load, load.array(), arrayLocation, index, elementKind, state, effects);
}
return false;
}
@@ -293,7 +336,7 @@
if (object != null) {
Pair<ValueNode, Object> pair = firstValueSet.get(object);
while (pair != null) {
- initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this);
+ initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, entry.overflowAccess, initialState.getReadCache().get(entry), this);
pair = (Pair<ValueNode, Object>) pair.getRight();
}
}
@@ -386,14 +429,14 @@
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, entry.kind, states);
+ mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, entry.overflowAccess, states);
}
}
}
}
}
- private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List<PEReadEliminationBlockState> states) {
+ private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, List<PEReadEliminationBlockState> states) {
ValueNode[] values = new ValueNode[states.size()];
values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this);
if (values[0] != null) {
@@ -407,12 +450,12 @@
values[i] = value;
}
- PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind), values[0].stamp().unrestricted());
+ PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), 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, kind), phiNode);
+ newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), phiNode);
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java Wed Oct 11 17:11:28 2017 -0700
@@ -28,6 +28,7 @@
import java.util.Iterator;
import java.util.List;
+import jdk.vm.ci.meta.ResolvedJavaType;
import org.graalvm.compiler.core.common.cfg.Loop;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.Node;
@@ -52,6 +53,7 @@
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
@@ -146,37 +148,40 @@
processIdentity(state, write.getLocationIdentity());
}
} else if (node instanceof UnsafeAccessNode) {
- if (node instanceof RawLoadNode) {
- RawLoadNode load = (RawLoadNode) node;
- if (load.getLocationIdentity().isSingle()) {
- ValueNode object = GraphUtil.unproxify(load.object());
- UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity());
- ValueNode cachedValue = state.getCacheEntry(identifier);
- if (cachedValue != null && areValuesReplaceable(load, cachedValue, considerGuards)) {
- effects.replaceAtUsages(load, cachedValue, load);
- addScalarAlias(load, cachedValue);
- deleted = true;
- } else {
- state.addCacheEntry(identifier, load);
+ ResolvedJavaType type = StampTool.typeOrNull(((UnsafeAccessNode) node).object());
+ if (type != null && !type.isArray()) {
+ if (node instanceof RawLoadNode) {
+ RawLoadNode load = (RawLoadNode) node;
+ if (load.getLocationIdentity().isSingle()) {
+ ValueNode object = GraphUtil.unproxify(load.object());
+ UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity());
+ ValueNode cachedValue = state.getCacheEntry(identifier);
+ if (cachedValue != null && areValuesReplaceable(load, cachedValue, considerGuards)) {
+ effects.replaceAtUsages(load, cachedValue, load);
+ addScalarAlias(load, cachedValue);
+ deleted = true;
+ } else {
+ state.addCacheEntry(identifier, load);
+ }
}
- }
- } else {
- assert node instanceof RawStoreNode;
- RawStoreNode write = (RawStoreNode) node;
- if (write.getLocationIdentity().isSingle()) {
- ValueNode object = GraphUtil.unproxify(write.object());
- UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
- ValueNode cachedValue = state.getCacheEntry(identifier);
+ } else {
+ assert node instanceof RawStoreNode;
+ RawStoreNode write = (RawStoreNode) node;
+ if (write.getLocationIdentity().isSingle()) {
+ ValueNode object = GraphUtil.unproxify(write.object());
+ UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
+ ValueNode cachedValue = state.getCacheEntry(identifier);
- ValueNode value = getScalarAlias(write.value());
- if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
- effects.deleteNode(write);
- deleted = true;
+ ValueNode value = getScalarAlias(write.value());
+ if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+ effects.deleteNode(write);
+ deleted = true;
+ }
+ processIdentity(state, write.getLocationIdentity());
+ state.addCacheEntry(identifier, value);
+ } else {
+ processIdentity(state, write.getLocationIdentity());
}
- processIdentity(state, write.getLocationIdentity());
- state.addCacheEntry(identifier, value);
- } else {
- processIdentity(state, write.getLocationIdentity());
}
}
} else if (node instanceof MemoryCheckpoint.Single) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java Wed Oct 11 17:11:28 2017 -0700
@@ -268,6 +268,9 @@
}
Word.Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod);
+ if (operation == null) {
+ throw bailout(b, "Cannot call method on a word value: " + wordMethod.format("%H.%n(%p)"));
+ }
switch (operation.opcode()) {
case NODE_CLASS:
assert args.length == 2;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Wed Oct 11 17:11:28 2017 -0700
@@ -527,7 +527,7 @@
final int bci = findNodeSourcePositionBCI(pos);
writeInt(bci);
StackTraceElement ste = findMethodStackTraceElement(method, bci, pos);
- if (ste != null) {
+ if (ste != null && ste.getFileName() != null) {
writePoolObject(ste.getFileName());
writeInt(ste.getLineNumber());
} else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java Wed Oct 11 17:11:28 2017 -0700
@@ -53,13 +53,11 @@
}
/**
- * Constructs a new option key given a default value and option key. The default value and the
- * type must not be <code>null</code>.
+ * Constructs a new option key given a default value and option key.
*
* @since 1.0
*/
public OptionKey(T defaultValue, OptionType<T> type) {
- Objects.requireNonNull(defaultValue);
Objects.requireNonNull(type);
this.defaultValue = defaultValue;
this.type = type;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java Wed Oct 11 17:11:28 2017 -0700
@@ -57,7 +57,6 @@
*/
public OptionType(String name, T defaultValue, Function<String, T> stringConverter, Consumer<T> validator) {
Objects.requireNonNull(name);
- Objects.requireNonNull(defaultValue);
Objects.requireNonNull(stringConverter);
Objects.requireNonNull(validator);
this.name = name;
@@ -133,7 +132,7 @@
return "OptionType[name=" + name + ", defaultValue=" + defaultValue + "]";
}
- private static Map<Class<?>, OptionType<?>> DEFAULTTYPES = new HashMap<>();
+ private static final Map<Class<?>, OptionType<?>> DEFAULTTYPES = new HashMap<>();
static {
DEFAULTTYPES.put(Boolean.class, new OptionType<>("Boolean", false, new Function<String, Boolean>() {
public Boolean apply(String t) {
@@ -200,13 +199,24 @@
/**
* Returns the default option type for a given value. Returns <code>null</code> if no default
- * option type is available for this Java type.
+ * option type is available for the Java type of this value.
*
* @since 1.0
*/
@SuppressWarnings("unchecked")
- public static <T> OptionType<T> defaultType(Object value) {
- return (OptionType<T>) DEFAULTTYPES.get(value.getClass());
+ public static <T> OptionType<T> defaultType(T value) {
+ return defaultType((Class<T>) value.getClass());
+ }
+
+ /**
+ * Returns the default option type for a class. Returns <code>null</code> if no default option
+ * type is available for this Java type.
+ *
+ * @since 1.0
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> OptionType<T> defaultType(Class<T> clazz) {
+ return (OptionType<T>) DEFAULTTYPES.get(clazz);
}
}