# HG changeset patch # User Thomas Wuerthinger # Date 1422727413 -3600 # Node ID db390d92bb16e0a28a97486a7fe727ac603d74b4 # Parent 687479c0cd3e097ea0d071d677c627b8c1695861# Parent 75da87c96605f46bf8f7b38acc5154af1143708f Merge. diff -r 687479c0cd3e -r db390d92bb16 CHANGELOG.md --- a/CHANGELOG.md Wed Jan 28 15:07:54 2015 +0100 +++ b/CHANGELOG.md Sat Jan 31 19:03:33 2015 +0100 @@ -6,6 +6,7 @@ ## `tip` ### Graal * Add utilities ModifiersProvider#isConcrete, ResolvedJavaMethod#hasBytecodes, ResolvedJavaMethod#hasReceiver to Graal API. +* Add `GraalDirectives` API, containing methods to influence compiler behavior for unittests and microbenchmarks. * ... ### Truffle diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java Sat Jan 31 19:03:33 2015 +0100 @@ -44,7 +44,7 @@ @Override public String toString() { - return "vstack(" + id + ")" + getKindSuffix(); + return "vstack:" + id + getKindSuffix(); } @Override diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/BlackholeDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/BlackholeDirectiveTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.api.directives.test; + +import java.lang.annotation.*; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; + +/** + * Tests for {@link GraalDirectives#blackhole}. + * + * There are two snippets for each kind: + * + * + */ +public class BlackholeDirectiveTest extends GraalCompilerTest { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + private @interface BlackholeSnippet { + boolean expectParameterUsage(); + } + + @BlackholeSnippet(expectParameterUsage = false) + public static int booleanSnippet(int arg) { + boolean b = arg > 3; + if (b) { + return 1; + } else { + return 1; + } + } + + @BlackholeSnippet(expectParameterUsage = true) + public static int blackholeBooleanSnippet(int arg) { + boolean b = arg > 3; + GraalDirectives.blackhole(b); + if (b) { + return 1; + } else { + return 1; + } + } + + @Test + public void testBoolean() { + test("booleanSnippet", 5); + test("blackholeBooleanSnippet", 5); + } + + @BlackholeSnippet(expectParameterUsage = false) + public static int intSnippet(int arg) { + int x = 42 + arg; + return x - arg; + } + + @BlackholeSnippet(expectParameterUsage = true) + public static int blackholeIntSnippet(int arg) { + int x = 42 + arg; + GraalDirectives.blackhole(x); + return x - arg; + } + + @Test + public void testInt() { + test("intSnippet", 17); + test("blackholeIntSnippet", 17); + } + + private static class Dummy { + private int x = 42; + } + + @BlackholeSnippet(expectParameterUsage = false) + public static int objectSnippet(int arg) { + Dummy obj = new Dummy(); + int ret = obj.x; + obj.x = arg; + return ret; + } + + @BlackholeSnippet(expectParameterUsage = true) + public static int blackholeObjectSnippet(int arg) { + Dummy obj = new Dummy(); + int ret = obj.x; + obj.x = arg; + GraalDirectives.blackhole(obj); + return ret; + } + + @Test + public void testObject() { + test("objectSnippet", 37); + test("blackholeObjectSnippet", 37); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class); + ParameterNode arg = graph.getParameter(0); + if (snippet.expectParameterUsage()) { + Assert.assertNotNull("couldn't find ParameterNode(0)", arg); + Assert.assertFalse("expected usages of " + arg, arg.hasNoUsages()); + } else { + Assert.assertTrue("expected no usages of ParameterNode", arg == null || arg.hasNoUsages()); + } + return true; + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/DeoptimizeDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/DeoptimizeDirectiveTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.api.directives.test; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.directives.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; + +public class DeoptimizeDirectiveTest extends GraalCompilerTest { + + public static boolean inCompiledCode() { + return GraalDirectives.inCompiledCode(); + } + + @Test + public void testInCompiledCode() { + ResolvedJavaMethod method = getResolvedJavaMethod("inCompiledCode"); + + Result interpreted = executeExpected(method, null); + assertEquals(new Result(false, null), interpreted); + + Result compiled = executeActual(method, null); + assertEquals(new Result(true, null), compiled); + } + + public static boolean deoptimizeSnippet() { + GraalDirectives.deoptimize(); + return GraalDirectives.inCompiledCode(); // should always return false + } + + public static boolean deoptimizeAndInvalidateSnippet() { + GraalDirectives.deoptimizeAndInvalidate(); + return GraalDirectives.inCompiledCode(); // should always return false + } + + @Test + public void testDeoptimize() { + test("deoptimizeSnippet"); + } + + private boolean testDeoptimizeCheckValid(ResolvedJavaMethod method) { + Result expected = executeExpected(method, null); + + InstalledCode code = getCode(method); + Result actual; + try { + actual = new Result(code.executeVarargs(), null); + } catch (Throwable e) { + actual = new Result(null, e); + } + + assertEquals(expected, actual); + return code.isValid(); + } + + @Test + public void testDeoptimizeAndInvalidate() { + ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeAndInvalidateSnippet"); + boolean valid = testDeoptimizeCheckValid(method); + Assert.assertFalse("code should be invalidated", valid); + } + + @Test + public void testDeoptimizeDontInvalidate() { + ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeSnippet"); + boolean valid = testDeoptimizeCheckValid(method); + Assert.assertTrue("code should still be valid", valid); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/IterationDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/IterationDirectiveTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.api.directives.test; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; + +public class IterationDirectiveTest extends GraalCompilerTest { + + public static int loopFrequencySnippet(int arg) { + int x = arg; + while (GraalDirectives.injectIterationCount(128, x > 1)) { + GraalDirectives.controlFlowAnchor(); // prevent loop peeling or unrolling + if (x % 2 == 0) { + x /= 2; + } else { + x = 3 * x + 1; + } + } + return x; + } + + @Test + public void testLoopFrequency() { + test("loopFrequencySnippet", 7); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + NodeIterable loopBeginNodes = graph.getNodes(LoopBeginNode.class); + Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count()); + + LoopBeginNode loopBeginNode = loopBeginNodes.first(); + Assert.assertEquals("loop frequency of " + loopBeginNode, 128, loopBeginNode.loopFrequency(), 0); + + return true; + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/OpaqueDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/OpaqueDirectiveTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.api.directives.test; + +import java.lang.annotation.*; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + +/** + * Tests for {@link GraalDirectives#opaque}. + * + * There are two snippets for each kind: + * + * + */ +public class OpaqueDirectiveTest extends GraalCompilerTest { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + private @interface OpaqueSnippet { + Class expectedReturnNode(); + } + + @OpaqueSnippet(expectedReturnNode = ConstantNode.class) + public static boolean booleanSnippet() { + return 5 > 3; + } + + @OpaqueSnippet(expectedReturnNode = ConditionalNode.class) + public static boolean opaqueBooleanSnippet() { + return 5 > GraalDirectives.opaque(3); + } + + @Test + public void testBoolean() { + test("booleanSnippet"); + test("opaqueBooleanSnippet"); + } + + @OpaqueSnippet(expectedReturnNode = ConstantNode.class) + public static int intSnippet() { + return 5 + 3; + } + + @OpaqueSnippet(expectedReturnNode = AddNode.class) + public static int opaqueIntSnippet() { + return 5 + GraalDirectives.opaque(3); + } + + @Test + public void testInt() { + test("intSnippet"); + test("opaqueIntSnippet"); + } + + @OpaqueSnippet(expectedReturnNode = ConstantNode.class) + public static double doubleSnippet() { + return 5. + 3.; + } + + @OpaqueSnippet(expectedReturnNode = AddNode.class) + public static double opaqueDoubleSnippet() { + return 5. + GraalDirectives.opaque(3.); + } + + @Test + public void testDouble() { + test("doubleSnippet"); + test("opaqueDoubleSnippet"); + } + + private static class Dummy { + } + + @OpaqueSnippet(expectedReturnNode = ConstantNode.class) + public static boolean objectSnippet() { + Object obj = new Dummy(); + return obj == null; + } + + @OpaqueSnippet(expectedReturnNode = ConditionalNode.class) + public static boolean opaqueObjectSnippet() { + Object obj = new Dummy(); + return GraalDirectives.opaque(obj) == null; + } + + @Test + public void testObject() { + test("objectSnippet"); + test("opaqueObjectSnippet"); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class); + for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) { + Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass()); + } + return true; + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ProbabilityDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ProbabilityDirectiveTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.api.directives.test; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; + +public class ProbabilityDirectiveTest extends GraalCompilerTest { + + public static int branchProbabilitySnippet(int arg) { + if (GraalDirectives.injectBranchProbability(0.125, arg > 0)) { + GraalDirectives.controlFlowAnchor(); // prevent removal of the if + return 1; + } else { + GraalDirectives.controlFlowAnchor(); // prevent removal of the if + return 2; + } + } + + @Test + public void testBranchProbability() { + test("branchProbabilitySnippet", 5); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + NodeIterable ifNodes = graph.getNodes(IfNode.class); + Assert.assertEquals("IfNode count", 1, ifNodes.count()); + + IfNode ifNode = ifNodes.first(); + AbstractBeginNode trueSuccessor = ifNode.trueSuccessor(); + Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(trueSuccessor), 0); + + return true; + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.api.directives; + +/** + * Directives that influence the compilation of methods by Graal. They don't influence the semantics + * of the code, but they are useful for unit testing and benchmarking. + */ +public final class GraalDirectives { + + public static final double LIKELY_PROBABILITY = 0.75; + public static final double UNLIKELY_PROBABILITY = 1.0 - LIKELY_PROBABILITY; + + public static final double SLOWPATH_PROBABILITY = 0.0001; + public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY; + + /** + * Directive for the compiler to fall back to the bytecode interpreter at this point. + */ + public static void deoptimize() { + } + + /** + * Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate + * the compiled code and reprofile the method. + */ + public static void deoptimizeAndInvalidate() { + } + + /** + * Returns a boolean value indicating whether the method is executed in Graal-compiled code. + */ + public static boolean inCompiledCode() { + return false; + } + + /** + * A call to this method will never be duplicated by control flow optimizations in the compiler. + */ + public static void controlFlowAnchor() { + } + + /** + * Injects a probability for the given condition into the profiling information of a branch + * instruction. The probability must be a value between 0.0 and 1.0 (inclusive). + * + * Example usage (it specifies that the likelihood for a to be greater than b is 90%): + * + * + * if (injectBranchProbability(0.9, a > b)) { + * // ... + * } + * + * + * There are predefined constants for commonly used probabilities (see + * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY}, + * {@link #FASTPATH_PROBABILITY} ). + * + * @param probability the probability value between 0.0 and 1.0 that should be injected + */ + public static boolean injectBranchProbability(double probability, boolean condition) { + assert probability >= 0.0 && probability <= 1.0; + return condition; + } + + /** + * Injects an average iteration count of a loop into the probability information of a loop exit + * condition. The iteration count specifies how often the condition is checked, i.e. in for and + * while loops it is one more than the body iteration count, and in do-while loops it is equal + * to the body iteration count. The iteration count must be >= 1.0. + * + * Example usage (it specifies that the expected iteration count of the loop condition is 500, + * so the iteration count of the loop body is 499): + * + * + * for (int i = 0; injectIterationCount(500, i < array.length); i++) { + * // ... + * } + * + * + * @param iterations the expected number of iterations that should be injected + */ + public static boolean injectIterationCount(double iterations, boolean condition) { + return injectBranchProbability(1. - 1. / iterations, condition); + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(boolean value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(byte value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(short value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(char value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(int value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(long value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(float value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(double value) { + } + + /** + * Consume a value, making sure the compiler doesn't optimize away the computation of this + * value, even if it is otherwise unused. + */ + @SuppressWarnings("unused") + public static void blackhole(Object value) { + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static boolean opaque(boolean value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static byte opaque(byte value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static short opaque(short value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static char opaque(char value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static int opaque(int value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static long opaque(long value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static float opaque(float value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static double opaque(double value) { + return value; + } + + /** + * Do nothing, but also make sure the compiler doesn't do any optimizations across this call. + * + * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 * + * opaque(3) will result in a real multiplication, because the compiler will not see that + * opaque(3) is a constant. + */ + public static T opaque(T value) { + return value; + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java --- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java Sat Jan 31 19:03:33 2015 +0100 @@ -41,7 +41,8 @@ Class value() default ClassSubstitution.class; /** - * Specifies the original class. + * Specifies the original class or classes if a single class is being used for multiple + * substitutions. *

* This method is provided for cases where the original class is not accessible (according to * Java language access control rules). @@ -49,7 +50,7 @@ * If the default value is specified for this element, then a non-default value must be given * for the {@link #value()} element. */ - String className() default ""; + String[] className() default {}; /** * Determines if the substitutions are for classes that may not be part of the runtime. diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java --- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java Sat Jan 31 19:03:33 2015 +0100 @@ -38,7 +38,9 @@ protected List computeValue(Class type) { Service[] names = getServiceImpls(type); if (names == null || names.length == 0) { - throw new InternalError(format("No implementations for %s found (ensure %s extends %s)", type.getSimpleName(), type.getSimpleName(), Service.class)); + throw new InternalError( + format("No implementations for %s found (ensure %s extends %s and that in suite.py the \"annotationProcessors\" attribute for the project enclosing %s includes \"com.oracle.graal.service.processor\")", + type.getSimpleName(), type.getSimpleName(), Service.class, type.getSimpleName())); } return Arrays.asList(names); } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Sat Jan 31 19:03:33 2015 +0100 @@ -44,6 +44,7 @@ import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.framemap.*; import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.stackslotalloc.*; import com.oracle.graal.phases.*; public class BaselineBytecodeParser extends AbstractBytecodeParser implements BytecodeParserTool { @@ -128,7 +129,6 @@ RegisterConfig registerConfig = null; FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig); - frameMapBuilder.requireMapping(lir); TargetDescription target = backend.getTarget(); CallingConvention cc = CodeUtil.getCallingConvention(backend.getProviders().getCodeCache(), CallingConvention.Type.JavaCallee, method, false); this.lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, method, null); @@ -153,22 +153,17 @@ try (Scope s = Debug.scope("Allocator")) { if (backend.shouldAllocateRegisters()) { LinearScan.allocate(target, lirGenRes); - } else if (!LocationMarker.Options.UseLocationMarker.getValue()) { - // build frame map for targets that do not allocate registers - lirGenRes.buildFrameMap(); } } - if (LocationMarker.Options.UseLocationMarker.getValue()) { - try (Scope s1 = Debug.scope("BuildFrameMap")) { - // build frame map - lirGenRes.buildFrameMap(); - Debug.dump(lir, "After FrameMap building"); - } - try (Scope s1 = Debug.scope("MarkLocations")) { - if (backend.shouldAllocateRegisters()) { - // currently we mark locations only if we do register allocation - LocationMarker.markLocations(lir, lirGenRes.getFrameMap()); - } + try (Scope s1 = Debug.scope("BuildFrameMap")) { + // build frame map + lirGenRes.buildFrameMap(new SimpleStackSlotAllocator()); + Debug.dump(lir, "After FrameMap building"); + } + try (Scope s1 = Debug.scope("MarkLocations")) { + if (backend.shouldAllocateRegisters()) { + // currently we mark locations only if we do register allocation + LocationMarker.markLocations(lir, lirGenRes.getFrameMap()); } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java Sat Jan 31 19:03:33 2015 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.java.*; import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; /** @@ -50,7 +51,7 @@ private final GraphBuilderConfiguration graphBuilderConfig; public CompilationResult generate(ResolvedJavaMethod method, int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, - CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts) { + CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts, Replacements replacements) { assert method.getCode() != null : "method must contain bytecodes: " + method; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -67,7 +67,7 @@ StructuredGraph graph = new StructuredGraph(javaMethod); GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(); - new GraphBuilderPhase.Instance(getMetaAccess(), conf, OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, conf, OptimisticOptimizations.ALL).apply(graph); HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); new CanonicalizerPhase(true).apply(graph, context); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.directives.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; @@ -524,7 +525,7 @@ try (Scope bds = Debug.scope("CompileBaseline", javaMethod, providers.getCodeCache())) { BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess()); OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL; - return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default, optimisticOpts); + return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default, optimisticOpts, getReplacements()); } catch (Throwable e) { throw Debug.handle(e); } @@ -720,7 +721,7 @@ StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner) : graph; lastCompiledGraph = graphToCompile; CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graphToCompile.method(), false); - Request request = new Request<>(graphToCompile, null, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), + Request request = new Request<>(graphToCompile, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default); return GraalCompiler.compile(request); } @@ -855,7 +856,7 @@ * @return cond */ protected static boolean branchProbability(double p, boolean cond) { - return cond; + return GraalDirectives.injectBranchProbability(p, cond); } /** @@ -867,7 +868,7 @@ * @return cond */ protected static boolean iterationCount(double i, boolean cond) { - return cond; + return GraalDirectives.injectIterationCount(i, cond); } /** diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTestSubstitutions.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTestSubstitutions.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTestSubstitutions.java Sat Jan 31 19:03:33 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,22 +24,11 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; @ClassSubstitution(GraalCompilerTest.class) class GraalCompilerTestSubstitutions { @MethodSubstitution - public static boolean branchProbability(double p, boolean cond) { - return BranchProbabilityNode.probability(p, cond); - } - - @MethodSubstitution - public static boolean iterationCount(double i, boolean cond) { - return BranchProbabilityNode.probability(1. - 1. / i, cond); - } - - @MethodSubstitution public static void breakpoint() { BreakpointNode.breakpoint(); } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -60,7 +60,7 @@ final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod"); final StructuredGraph graph = parseEager(method); CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); - final CompilationResult cr = compileGraph(graph, null, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), + final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default); for (Infopoint sp : cr.getInfopoints()) { assertNotNull(sp.reason); @@ -83,7 +83,7 @@ assertTrue(graphLineSPs > 0); CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); PhaseSuite graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()); - final CompilationResult cr = compileGraph(graph, null, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, + final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default); int lineSPs = 0; for (Infopoint sp : cr.getInfopoints()) { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Sat Jan 31 19:03:33 2015 +0100 @@ -151,8 +151,8 @@ ResolvedJavaMethod method = getResolvedJavaMethod(snippet); graph = new StructuredGraph(method); try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) { - new GraphBuilderPhase.Instance(getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); Assumptions assumptions = new Assumptions(false); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); new DeadCodeEliminationPhase().apply(graph); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.compiler.test.tutorial; + +import org.junit.*; + +import com.oracle.graal.api.code.*; + +/** + * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at + * the examples in IGV (the graph visualization tool), use the options -G:Dump and -G:MethodFilter. + * For example, run the first test case using + * + *

+ * mx unittest -G:Dump= -G:MethodFilter=String.hashCode GraalTutorial#testStringHashCode
+ * 
+ */ +public class GraalTutorial extends InvokeGraal { + + /* + * A simple Graal compilation example: Compile the method String.hashCode() + */ + + @Test + public void testStringHashCode() throws InvalidInstalledCodeException { + InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode")); + + int result = (int) installedCode.executeVarargs("Hello World"); + Assert.assertEquals(-862545276, result); + } + + /* + * Tutorial example for speculative optimizations. + */ + + int f1; + int f2; + + public void speculativeOptimization(boolean flag) { + f1 = 41; + if (flag) { + f2 = 42; + return; + } + f2 = 43; + } + + @Test + public void testSpeculativeOptimization() throws InvalidInstalledCodeException { + /* + * Collect profiling information by running the method in the interpreter. + */ + for (int i = 0; i < 10000; i++) { + speculativeOptimization(false); + } + + /* + * Warmup to collect profiling information is done, now we compile the method. Since the + * value of "flag" was always false during the warmup, the compiled code speculates that the + * value remains false. + */ + + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization")); + f1 = 0; + f2 = 0; + compiledMethod.executeVarargs(this, true); + Assert.assertEquals(41, f1); + Assert.assertEquals(42, f2); + + /* + * We executed the compiled method with a "flag" value that triggered deoptimization (since + * the warmup always used the different "flag" value). The interpreter updated the profiling + * information, so the second compilation does not perform the speculative optimization. + */ + + compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization")); + f1 = 0; + f2 = 0; + compiledMethod.executeVarargs(this, false); + Assert.assertEquals(41, f1); + Assert.assertEquals(43, f2); + } + + /* + * Tutorial example for snippets and lowering. + */ + + static class A { + } + + static class B extends A { + } + + public static int instanceOfUsage(Object obj) { + if (obj instanceof A) { + return 42; + } else { + return 0; + } + } + + @Test + public void testInstanceOfUsage() throws InvalidInstalledCodeException { + A a = new A(); + + /* Allocate an (unsued) instance of B so that the class B gets loaded. */ + @SuppressWarnings("unused") + B b = new B(); + + for (int i = 0; i < 10000; i++) { + instanceOfUsage(a); + } + + /* Warmup to collect profiling information is done, now compile the method. */ + + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage")); + + int result = (int) compiledMethod.executeVarargs(a); + Assert.assertEquals(42, result); + } + + /* + * Tutorial example for intrinsic methods. + */ + + public static double intrinsicUsage(double val) { + return Math.sin(val); + } + + @Test + public void testIntrinsicUsage() throws InvalidInstalledCodeException { + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage")); + + double result = (double) compiledMethod.executeVarargs(42d); + Assert.assertEquals(Math.sin(42), result, 0); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.compiler.test.tutorial; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.atomic.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.runtime.*; + +/** + * Sample code that shows how to invoke Graal from an application. + */ +public class InvokeGraal { + + protected final Backend backend; + protected final Providers providers; + protected final MetaAccessProvider metaAccess; + protected final CodeCacheProvider codeCache; + protected final TargetDescription target; + + public InvokeGraal() { + /* Ask the hosting Java VM for the entry point object to the Graal API. */ + RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class); + + /* The default backend (architecture, VM configuration) that the hosting VM is running on. */ + backend = runtimeProvider.getHostBackend(); + /* Access to all of the Graal API providers, as implemented by the hosting VM. */ + providers = backend.getProviders(); + /* Some frequently used providers and configuration objects. */ + metaAccess = providers.getMetaAccess(); + codeCache = providers.getCodeCache(); + target = codeCache.getTarget(); + } + + private static AtomicInteger compilationId = new AtomicInteger(); + + /** + * The simplest way to compile a method, using the default behavior for everything. + */ + protected InstalledCode compileAndInstallMethod(ResolvedJavaMethod method) { + /* Ensure every compilation gets a unique number, visible in IGV. */ + try (Scope s = Debug.scope("compileAndInstallMethod", new DebugDumpScope(String.valueOf(compilationId.incrementAndGet()), true))) { + + /* + * The graph that is compiled. We leave it empty (no nodes added yet). This means that + * it will be filled according to the graphBuilderSuite defined below. + */ + StructuredGraph graph = new StructuredGraph(method); + + /* + * The phases used to build the graph. Usually this is just the GraphBuilderPhase. If + * the graph already contains nodes, it is ignored. + */ + PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite(); + + /* + * The optimization phases that are applied to the graph. This is the main configuration + * point for Graal. Add or remove phases to customize your compilation. + */ + Suites suites = backend.getSuites().createSuites(); + + /* + * The calling convention for the machine code. You should have a very good reason + * before you switch to a different calling convention than the one that the VM provides + * by default. + */ + CallingConvention callingConvention = CodeUtil.getCallingConvention(codeCache, Type.JavaCallee, method, false); + + /* + * We want Graal to perform all speculative optimisitic optimizations, using the + * profiling information that comes with the method (collected by the interpreter) for + * speculation. + */ + OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL; + ProfilingInfo profilingInfo = method.getProfilingInfo(); + + /* The default class and configuration for compilation results. */ + CompilationResult compilationResult = new CompilationResult(); + CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default; + + /* Advanced configuration objects that are not mandatory. */ + Map cache = null; + SpeculationLog speculationLog = null; + + /* Invoke the whole Graal compilation pipeline. */ + GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, + compilationResult, factory); + + /* + * Install the compilation result into the VM, i.e., copy the byte[] array that contains + * the machine code into an actual executable memory location. + */ + InstalledCode installedCode = codeCache.addMethod(method, compilationResult, null, null); + + return installedCode; + } catch (Throwable ex) { + throw Debug.handle(ex); + } + } + + /** + * Look up a method using Java reflection and convert it to the Graal API method object. + */ + protected ResolvedJavaMethod findMethod(Class declaringClass, String name) { + Method reflectionMethod = null; + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(name)) { + assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName(); + reflectionMethod = m; + } + } + assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName(); + return metaAccess.lookupJavaMethod(reflectionMethod); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,589 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.compiler.test.tutorial; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; + +/** + * A simple context-insensitive static analysis based on the Graal API. It is intended for + * educational purposes, not for use in production. Only a limited set of Java functionality is + * supported to keep the code minimal. + *

+ * The analysis builds a directed graph of {@link TypeFlow type flows}. If a type is added to type + * flow, it is propagated to all {@link TypeFlow#uses uses} of the type flow. Types are propagated + * using a {@link #worklist} of changed type flows until a fixpoint is reached, i.e., until no more + * types need to be added to any type state. + *

+ * The type flows are constructed from a high-level Graal graph by the {@link TypeFlowBuilder}. All + * nodes that operate on {@link Kind#Object object} values are converted to the appropriate type + * flows. The analysis is context insensitive: every Java field has {@link Results#lookupField one + * list} of types assigned to the field; every Java method has {@link Results#lookupMethod one + * state} for each {@link MethodState#formalParameters parameter} as well as the + * {@link MethodState#formalReturn return value}. + */ +public class StaticAnalysis { + /** Access to type, method, and fields using the Graal API. */ + private final MetaAccessProvider metaAccess; + /** Access to platform dependent stamps. */ + private final StampProvider stampProvider; + /** The results of the static analysis. */ + private final Results results; + /** Worklist for fixpoint iteration. */ + private final Deque worklist; + + public StaticAnalysis(MetaAccessProvider metaAccess, StampProvider stampProvider) { + this.metaAccess = metaAccess; + this.stampProvider = stampProvider; + this.results = new Results(); + this.worklist = new ArrayDeque<>(); + } + + /** + * Adds a root method to the static analysis. The method must be static and must not have any + * parameters, because the possible types of the parametes would not be known. + */ + public void addMethod(ResolvedJavaMethod method) { + if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) { + error("Entry point method is not static or has parameters: " + method.format("%H.%n(%p)")); + } + addToWorklist(results.lookupMethod(method)); + } + + /** + * Performs the fixed-point analysis that finds all methods transitively reachable from the + * {@link #addMethod root methods}. + */ + public void finish() { + while (!worklist.isEmpty()) { + worklist.removeFirst().process(); + } + } + + /** + * Returns the static analysis results computed by {@link StaticAnalysis#finish}. + */ + public Results getResults() { + return results; + } + + protected void addToWorklist(WorklistEntry task) { + worklist.addLast(task); + } + + protected static RuntimeException error(String msg) { + throw GraalInternalError.shouldNotReachHere(msg); + } + + /** + * Base class for all work items that can be {@link #addToWorklist added to the worklist}. + */ + abstract class WorklistEntry { + protected abstract void process(); + } + + /** + * The results computed by the static analysis. + */ + public class Results { + private final TypeFlow allInstantiatedTypes; + private final Map fields; + private final Map methods; + + protected Results() { + allInstantiatedTypes = new TypeFlow(); + fields = new HashMap<>(); + methods = new HashMap<>(); + } + + /** + * All {@link TypeFlow#getTypes() types} that are found to be instantiated, i.e., all types + * allocated by the reachable instance and array allocation bytecodes. + */ + public TypeFlow getAllInstantiatedTypes() { + return allInstantiatedTypes; + } + + /** + * All {@link TypeFlow#getTypes() types} that the given field can have, i.e., all types + * assigned by the reachable field store bytecodes. + */ + public TypeFlow lookupField(ResolvedJavaField field) { + TypeFlow result = fields.get(field); + if (result == null) { + result = new TypeFlow(); + fields.put(field, result); + } + return result; + } + + /** + * All {@link TypeFlow#getTypes() types} that {@link MethodState#formalParameters + * parameters} and {@link MethodState#formalReturn return value} of the given method can + * have. + */ + public MethodState lookupMethod(ResolvedJavaMethod method) { + MethodState result = methods.get(method); + if (result == null) { + result = new MethodState(method); + methods.put(method, result); + } + return result; + } + } + + /** + * The {@link TypeFlow#getTypes() types} of the parameters and return value of a method. Also + * serves as the worklist element to parse the bytecodes of the method. + */ + public class MethodState extends WorklistEntry { + private final ResolvedJavaMethod method; + private final TypeFlow[] formalParameters; + private final TypeFlow formalReturn; + private boolean processed; + + protected MethodState(ResolvedJavaMethod method) { + this.method = method; + + formalParameters = new TypeFlow[method.getSignature().getParameterCount(!method.isStatic())]; + for (int i = 0; i < formalParameters.length; i++) { + formalParameters[i] = new TypeFlow(); + } + formalReturn = new TypeFlow(); + } + + /** + * All {@link TypeFlow#getTypes() types} that the parameters of this method can have. + */ + public TypeFlow[] getFormalParameters() { + return formalParameters; + } + + /** + * All {@link TypeFlow#getTypes() types} that the return value of this method can have. + */ + public TypeFlow getFormalReturn() { + return formalReturn; + } + + @Override + protected void process() { + if (!processed) { + /* We want to process a method only once. */ + processed = true; + + /* + * Build the Graal graph for the method using the bytecode parser provided by Graal. + */ + + StructuredGraph graph = new StructuredGraph(method); + /* + * Support for graph dumping, IGV uses this information to show the method name of a + * graph. + */ + try (Scope scope = Debug.scope("graph building", graph)) { + /* + * We want all types to be resolved by the graph builder, i.e., we want classes + * referenced by the bytecodes to be loaded and initialized. Since we do not run + * the code before static analysis, the classes would otherwise be not loaded + * yet and the bytecode parser would only create a graph. + */ + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault().withOmitAllExceptionEdges(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 + * handle the Graal nodes for throwing and handling exceptions. + */ + graphBuilderConfig = graphBuilderConfig.withOmitAllExceptionEdges(true); + /* + * We do not want Graal to perform any speculative optimistic optimizations, + * i.e., we do not want to use profiling information. Since we do not run the + * code before static analysis, the profiling information is empty and therefore + * wrong. + */ + OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; + Assumptions assumptions = new Assumptions(false); + + GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts); + graphBuilder.apply(graph); + } catch (Throwable ex) { + Debug.handle(ex); + } + + /* + * Build the type flow graph from the Graal graph, i.e., process all nodes that are + * deal with objects. + */ + + TypeFlowBuilder typeFlowBuilder = new TypeFlowBuilder(graph); + typeFlowBuilder.apply(); + } + } + } + + /** + * The active element during static analysis: types are added until a fixed point is reached. + * When a new type is added, it is propagated to all usages by putting this element on the + * {@link StaticAnalysis#addToWorklist worklist}. + */ + public class TypeFlow extends WorklistEntry { + private final Set types; + private final Set uses; + + protected TypeFlow() { + types = new HashSet<>(); + uses = new HashSet<>(); + } + + /** Returns the types of this element. */ + public Set getTypes() { + return types; + } + + /** + * Adds new types to this element. If that changes the state of this element, it is added to + * the {@link StaticAnalysis#addToWorklist worklist} in order to propagate the added types + * to all usages. + */ + protected void addTypes(Set newTypes) { + if (types.addAll(newTypes)) { + addToWorklist(this); + } + } + + /** + * Adds a new use to this element. All types of this element are propagated to the new + * usage. + */ + protected void addUse(TypeFlow use) { + if (uses.add(use)) { + use.addTypes(types); + } + } + + /** + * Processing of the worklist element: propagate the types to all usages. That in turn can + * add the usages to the worklist (if the types of the usage are changed). + */ + @Override + protected void process() { + for (TypeFlow use : uses) { + use.addTypes(types); + } + } + } + + /** + * The active element for method invocations. For {@link InvokeKind#Virtual virtual} and + * {@link InvokeKind#Interface interface} calls, the {@link TypeFlow#getTypes() types} of this + * node are the receiver types. When a new receiver type is added, a new callee might be added. + * Adding a new callee means liking the type flow of the actual parameters with the formal + * parameters of the callee, and linking the return value of the callee with the return value + * state of the invocation. + * + * Statically bindable methods calls ({@link InvokeKind#Static static} and + * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for + * simplicity. + */ + + class InvokeTypeFlow extends TypeFlow { + private final MethodCallTargetNode callTarget; + private final TypeFlow[] actualParameters; + private final TypeFlow actualReturn; + private final Set callees; + + protected InvokeTypeFlow(MethodCallTargetNode callTarget, TypeFlow[] actualParameterFlows, TypeFlow actualReturnFlow) { + this.callTarget = callTarget; + this.actualParameters = actualParameterFlows; + this.actualReturn = actualReturnFlow; + this.callees = new HashSet<>(); + } + + private void linkCallee(ResolvedJavaMethod callee) { + if (callees.add(callee)) { + /* We have added a new callee. */ + + /* + * Connect the actual parameters of the invocation with the formal parameters of the + * callee. + */ + MethodState calleeState = results.lookupMethod(callee); + for (int i = 0; i < actualParameters.length; i++) { + if (actualParameters[i] != null) { + actualParameters[i].addUse(calleeState.formalParameters[i]); + } + } + + /* + * Connect the formal return value of the callee with the actual return value of the + * invocation. + */ + if (actualReturn != null) { + calleeState.formalReturn.addUse(actualReturn); + } + addToWorklist(calleeState); + } + } + + @Override + protected void process() { + if (callTarget.invokeKind().isDirect()) { + /* Static and special calls: link the statically known callee method. */ + linkCallee(callTarget.targetMethod()); + } else { + /* Virtual and interface call: Iterate all receiver types. */ + for (ResolvedJavaType type : getTypes()) { + /* + * Resolve the method call for one exact receiver type. The method linking + * semantics of Java are complicated, but fortunatley we can use the linker of + * the hosting Java VM. The Graal API exposes this functionality. + */ + ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), callTarget.invoke().getContextType()); + + /* + * Since the static analysis is conservative, the list of receiver types can + * contain types that actually do not provide the method to be called. Ignore + * these. + */ + if (method != null && !method.isAbstract()) { + linkCallee(method); + } + } + } + super.process(); + } + } + + /** + * Converts the Graal nodes of a method to a type flow graph. The main part of the algorithm is + * a reverse-postorder iteration of the Graal nodes, which is provided by the base class + * {@link StatelessPostOrderNodeIterator}. + */ + class TypeFlowBuilder extends StatelessPostOrderNodeIterator { + private final StructuredGraph graph; + private final MethodState methodState; + /** + * Mapping from Graal nodes to type flows. This uses an efficient Graal-provided + * {@link NodeMap collection class}. + */ + private final NodeMap typeFlows; + + protected TypeFlowBuilder(StructuredGraph graph) { + super(graph.start()); + + this.graph = graph; + this.methodState = results.lookupMethod(graph.method()); + this.typeFlows = new NodeMap<>(graph); + } + + /** + * Register the type flow node for a Graal node. + */ + private void registerFlow(ValueNode node, TypeFlow flow) { + /* + * We ignore intermediate nodes used by Graal that, e.g., add more type information or + * encapsulate values flowing out of loops. + */ + ValueNode unproxiedNode = GraphUtil.unproxify(node); + + assert typeFlows.get(unproxiedNode) == null : "overwriting existing value"; + typeFlows.set(unproxiedNode, flow); + } + + /** + * Lookup the type flow node for a Graal node. + */ + private TypeFlow lookupFlow(ValueNode node) { + ValueNode unproxiedNode = GraphUtil.unproxify(node); + TypeFlow result = typeFlows.get(unproxiedNode); + if (result == null) { + /* + * This is only the prototype of a static analysis, the handling of many Graal nodes + * (such as array accesses) is not implemented. + */ + throw error("Node is not supported yet by static analysis: " + node.getClass().getName()); + } + return result; + } + + private boolean isObject(ValueNode node) { + return node.getKind() == Kind.Object; + } + + @Override + public void apply() { + /* + * Before the reverse-postorder iteration of fixed nodes, we handle some classes of + * floating nodes. + */ + for (Node n : graph.getNodes()) { + if (n instanceof ParameterNode) { + /* + * Incoming method parameter already have a type flow created by the + * MethodState. + */ + ParameterNode node = (ParameterNode) n; + if (isObject(node)) { + registerFlow(node, methodState.formalParameters[(node.index())]); + } + } else if (n instanceof ValuePhiNode) { + /* + * Phi functions for loops are cyclic. We create the type flow here (before + * processing any loop nodes), but link the phi values only later (after + * processing of all loop nodes. + */ + ValuePhiNode node = (ValuePhiNode) n; + if (isObject(node)) { + registerFlow(node, new TypeFlow()); + } + } else if (n instanceof ConstantNode) { + /* Constants have a known type. */ + ConstantNode node = (ConstantNode) n; + JavaConstant constant = node.asJavaConstant(); + if (constant.isNull()) { + registerFlow(node, new TypeFlow()); + } + } + } + + super.apply(); + + for (Node n : graph.getNodes()) { + if (n instanceof ValuePhiNode) { + /* + * Post-processing of phi functions. Now the type flow for all input values has + * been created, so we can link the type flows together. + */ + ValuePhiNode node = (ValuePhiNode) n; + if (isObject(node)) { + TypeFlow phiFlow = lookupFlow(node); + for (ValueNode value : node.values()) { + lookupFlow(value).addUse(phiFlow); + } + } + } + } + } + + private void allocation(ValueNode node, ResolvedJavaType type) { + /* + * The type flow of allocation nodes is one exact type. This is the source of the + * fixpoint iteration, the types are propagated downwards from these sources. + */ + TypeFlow flow = new TypeFlow(); + flow.addTypes(Collections.singleton(type)); + registerFlow(node, flow); + flow.addUse(results.getAllInstantiatedTypes()); + } + + @Override + protected void node(FixedNode n) { + if (n instanceof NewInstanceNode) { + NewInstanceNode node = (NewInstanceNode) n; + allocation(node, node.instanceClass()); + } else if (n instanceof NewArrayNode) { + NewArrayNode node = (NewArrayNode) n; + allocation(node, node.elementType().getArrayClass()); + + } else if (n instanceof LoadFieldNode) { + /* + * The type flow of a field load is the type flow of the field itself. It + * accumulates all types ever stored to the field. + */ + LoadFieldNode node = (LoadFieldNode) n; + if (isObject(node)) { + registerFlow(node, results.lookupField(node.field())); + } + } else if (n instanceof StoreFieldNode) { + /* + * Connect the type flow of the stored value with the type flow of the field. + */ + StoreFieldNode node = (StoreFieldNode) n; + if (isObject(node.value())) { + TypeFlow fieldFlow = results.lookupField(node.field()); + lookupFlow(node.value()).addUse(fieldFlow); + } + + } else if (n instanceof ReturnNode) { + /* + * Connect the type flow of the returned value with the formal return type flow of + * the MethodState. + */ + ReturnNode node = (ReturnNode) n; + if (node.result() != null && isObject(node.result())) { + lookupFlow(node.result()).addUse(methodState.formalReturn); + } + + } else if (n instanceof Invoke) { + /* + * Create the InvokeTypeFlow, which performs all the linking of actual and formal + * parameter values with all identified callees. + */ + Invoke invoke = (Invoke) n; + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + + TypeFlow[] actualParameters = new TypeFlow[callTarget.arguments().size()]; + for (int i = 0; i < actualParameters.length; i++) { + ValueNode actualParam = callTarget.arguments().get(i); + if (isObject(actualParam)) { + actualParameters[i] = lookupFlow(actualParam); + } + } + TypeFlow actualReturn = null; + if (isObject(invoke.asNode())) { + actualReturn = new TypeFlow(); + registerFlow(invoke.asNode(), actualReturn); + } + + InvokeTypeFlow invokeFlow = new InvokeTypeFlow(callTarget, actualParameters, actualReturn); + + if (callTarget.invokeKind().isIndirect()) { + /* + * For virtual and interface calls, new receiver types can lead to new callees. + * Connect the type flow of the receiver with the invocation flow. + */ + lookupFlow(callTarget.arguments().get(0)).addUse(invokeFlow); + } + /* + * Ensure the invocation is on the worklist at least once, even if it is a static + * call with not parameters that does not involve any type flows. + */ + addToWorklist(invokeFlow); + } + } + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysisTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysisTests.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.compiler.test.tutorial; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.compiler.test.tutorial.StaticAnalysis.MethodState; +import com.oracle.graal.compiler.test.tutorial.StaticAnalysis.TypeFlow; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.runtime.*; + +public class StaticAnalysisTests { + + static class A { + Object foo(Object arg) { + return arg; + } + } + + static class B extends A { + @Override + Object foo(Object arg) { + if (arg instanceof Data) { + return ((Data) arg).f; + } else { + return super.foo(arg); + } + } + } + + static class Data { + Object f; + } + + private final MetaAccessProvider metaAccess; + private final StampProvider stampProvider; + + public StaticAnalysisTests() { + Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); + Providers providers = backend.getProviders(); + this.metaAccess = providers.getMetaAccess(); + this.stampProvider = providers.getStampProvider(); + } + + static void test01Entry() { + A a = new A(); + a.foo(null); + } + + @Test + public void test01() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class)); + assertEquals(f(sa, Data.class, "f")); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1]); + assertEquals(m(sa, A.class, "foo").getFormalReturn()); + } + + static void test02Entry() { + A a = new A(); + a.foo(new Data()); + + B b = new B(); + b.foo(null); + } + + @Test + public void test02() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class)); + assertEquals(f(sa, Data.class, "f")); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class)); + assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]); + assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class)); + } + + static void test03Entry() { + Data data = new Data(); + data.f = new Integer(42); + + A a = new A(); + a.foo(new Data()); + + B b = new B(); + b.foo(null); + } + + @Test + public void test03() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class), t(Integer.class)); + assertEquals(f(sa, Data.class, "f"), t(Integer.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class)); + assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]); + assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class), t(Integer.class)); + } + + static void test04Entry() { + Data data = null; + for (int i = 0; i < 2; i++) { + if (i == 0) { + data = new Data(); + } else if (i == 1) { + data.f = new Integer(42); + } + } + + A a = new A(); + a.foo(data); + } + + @Test + public void test04() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(Data.class), t(Integer.class)); + assertEquals(f(sa, Data.class, "f"), t(Integer.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class)); + assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class)); + } + + private MethodState m(StaticAnalysis sa, Class declaringClass, String name) { + return sa.getResults().lookupMethod(findMethod(declaringClass, name)); + } + + private TypeFlow f(StaticAnalysis sa, Class declaringClass, String name) { + return sa.getResults().lookupField(findField(declaringClass, name)); + } + + private static void assertEquals(TypeFlow actual, Object... expected) { + Collection actualTypes = actual.getTypes(); + if (actualTypes.size() != expected.length || !actualTypes.containsAll(Arrays.asList(expected))) { + Assert.fail(actualTypes + " != " + Arrays.asList(expected)); + } + } + + private ResolvedJavaType t(Class clazz) { + return metaAccess.lookupJavaType(clazz); + } + + private ResolvedJavaMethod findMethod(Class declaringClass, String name) { + Method reflectionMethod = null; + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(name)) { + assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName(); + reflectionMethod = m; + } + } + assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName(); + return metaAccess.lookupJavaMethod(reflectionMethod); + } + + private ResolvedJavaField findField(Class declaringClass, String name) { + Field reflectionField; + try { + reflectionField = declaringClass.getDeclaredField(name); + } catch (NoSuchFieldException | SecurityException ex) { + throw new AssertionError(ex); + } + return metaAccess.lookupJavaField(reflectionField); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sat Jan 31 19:03:33 2015 +0100 @@ -46,6 +46,7 @@ import com.oracle.graal.lir.constopt.*; import com.oracle.graal.lir.framemap.*; import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.stackslotalloc.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; @@ -131,7 +132,6 @@ */ public static class Request { public final StructuredGraph graph; - public final Object stub; public final CallingConvention cc; public final ResolvedJavaMethod installedCodeOwner; public final Providers providers; @@ -151,7 +151,6 @@ * @param cc the calling convention for calls to the code compiled for {@code graph} * @param installedCodeOwner the method the compiled code will be associated with once * installed. This argument can be null. - * @param stub * @param providers * @param backend * @param target @@ -164,11 +163,10 @@ * @param compilationResult * @param factory */ - public Request(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target, + public Request(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target, Map cache, PhaseSuite graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, T compilationResult, CompilationResultBuilderFactory factory) { this.graph = graph; - this.stub = stub; this.cc = cc; this.installedCodeOwner = installedCodeOwner; this.providers = providers; @@ -203,11 +201,11 @@ * installed. This argument can be null. * @return the result of the compilation */ - public static T compileGraph(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, + public static T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target, Map cache, PhaseSuite graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, T compilationResult, CompilationResultBuilderFactory factory) { - return compile(new Request<>(graph, stub, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, - compilationResult, factory)); + return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, compilationResult, + factory)); } /** @@ -220,7 +218,7 @@ try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) { Assumptions assumptions = new Assumptions(OptAssumptions.getValue()); SchedulePhase schedule = emitFrontEnd(r.providers, r.target, r.graph, assumptions, r.cache, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.speculationLog, r.suites); - emitBackEnd(r.graph, r.stub, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null); + emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null); } catch (Throwable e) { throw Debug.handle(e); } @@ -323,7 +321,6 @@ } try (Scope ds = Debug.scope("BackEnd", lir)) { FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig); - frameMapBuilder.requireMapping(lir); LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, graph.method(), stub); LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes); NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen); @@ -351,25 +348,26 @@ try (Scope s = Debug.scope("Allocator", nodeLirGen)) { if (backend.shouldAllocateRegisters()) { LinearScan.allocate(target, lirGenRes); - } else if (!LocationMarker.Options.UseLocationMarker.getValue()) { - // build frame map for targets that do not allocate registers - lirGenRes.buildFrameMap(); } } catch (Throwable e) { throw Debug.handle(e); } - if (LocationMarker.Options.UseLocationMarker.getValue()) { - try (Scope s1 = Debug.scope("BuildFrameMap")) { - // build frame map - lirGenRes.buildFrameMap(); - Debug.dump(lir, "After FrameMap building"); + try (Scope s1 = Debug.scope("BuildFrameMap")) { + // build frame map + final StackSlotAllocator allocator; + if (LSStackSlotAllocator.Options.EnableLSStackSlotAllocation.getValue()) { + allocator = new LSStackSlotAllocator(); + } else { + allocator = new SimpleStackSlotAllocator(); } - try (Scope s1 = Debug.scope("MarkLocations")) { - if (backend.shouldAllocateRegisters()) { - // currently we mark locations only if we do register allocation - LocationMarker.markLocations(lir, lirGenRes.getFrameMap()); - } + lirGenRes.buildFrameMap(allocator); + Debug.dump(lir, "After FrameMap building"); + } + try (Scope s1 = Debug.scope("MarkLocations")) { + if (backend.shouldAllocateRegisters()) { + // currently we mark locations only if we do register allocation + LocationMarker.markLocations(lir, lirGenRes.getFrameMap()); } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sat Jan 31 19:03:33 2015 +0100 @@ -1640,67 +1640,6 @@ return new IntervalWalker(this, oopIntervals, nonOopIntervals); } - /** - * Visits all intervals for a frame state. The frame state use this information to build the OOP - * maps. - */ - private void markFrameLocations(IntervalWalker iw, LIRInstruction op, LIRFrameState info, FrameMap frameMap) { - Debug.log("creating oop map at opId %d", op.id()); - - // walk before the current operation . intervals that start at - // the operation (i.e. output operands of the operation) are not - // included in the oop map - iw.walkBefore(op.id()); - - // TODO(je) we could pass this as parameter - AbstractBlock block = blockForId(op.id()); - - // Iterate through active intervals - for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { - Value operand = interval.operand; - - assert interval.currentFrom() <= op.id() && op.id() <= interval.currentTo() : "interval should not be active otherwise"; - assert isVariable(interval.operand) : "fixed interval found"; - - // Check if this range covers the instruction. Intervals that - // start or end at the current operation are not included in the - // oop map, except in the case of patching moves. For patching - // moves, any intervals which end at this instruction are included - // in the oop map since we may safepoint while doing the patch - // before we've consumed the inputs. - if (op.id() < interval.currentTo() && !isIllegal(interval.location())) { - // caller-save registers must not be included into oop-maps at calls - assert !op.destroysCallerSavedRegisters() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten"; - - info.markLocation(interval.location(), frameMap); - - // Spill optimization: when the stack value is guaranteed to be always correct, - // then it must be added to the oop map even if the interval is currently in a - // register - int spillPos = interval.spillDefinitionPos(); - if (interval.spillState() != SpillState.SpillInDominator) { - if (interval.alwaysInMemory() && op.id() > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) { - assert interval.spillDefinitionPos() > 0 : "position not set correctly"; - assert spillPos > 0 : "position not set correctly"; - assert interval.spillSlot() != null : "no spill slot assigned"; - assert !isRegister(interval.operand) : "interval is on stack : so stack slot is registered twice"; - info.markLocation(interval.spillSlot(), frameMap); - } - } else { - AbstractBlock spillBlock = blockForId(spillPos); - if (interval.alwaysInMemory() && !interval.location().equals(interval.spillSlot())) { - if ((spillBlock.equals(block) && op.id() > spillPos) || dominates(spillBlock, block)) { - assert spillPos > 0 : "position not set correctly"; - assert interval.spillSlot() != null : "no spill slot assigned"; - assert !isRegister(interval.operand) : "interval is on stack : so stack slot is registered twice"; - info.markLocation(interval.spillSlot(), frameMap); - } - } - } - } - } - } - private boolean isCallerSave(Value operand) { return attributes(asRegister(operand)).isCallerSave(); } @@ -1744,20 +1683,11 @@ return result; } - private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) { - if (!LocationMarker.Options.UseLocationMarker.getValue()) { - FrameMap frameMap = res.getFrameMap(); - info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters); - markFrameLocations(iw, op, info, frameMap); - } - + private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) { info.forEachState(op, this::debugInfoProcedure); - if (!LocationMarker.Options.UseLocationMarker.getValue()) { - info.finish(op, res.getFrameMap()); - } } - private void assignLocations(List instructions, final IntervalWalker iw) { + private void assignLocations(List instructions) { int numInst = instructions.size(); boolean hasDead = false; @@ -1792,7 +1722,7 @@ op.forEachOutput(assignProc); // compute reference map and debug information - op.forEachState((inst, state) -> computeDebugInfo(iw, inst, state)); + op.forEachState((inst, state) -> computeDebugInfo(inst, state)); // remove useless moves if (move != null) { @@ -1810,41 +1740,15 @@ } private void assignLocations() { - IntervalWalker iw = initIntervalWalker(IS_STACK_INTERVAL); try (Indent indent = Debug.logAndIndent("assign locations")) { for (AbstractBlock block : sortedBlocks) { try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { - assignLocations(ir.getLIRforBlock(block), iw); + assignLocations(ir.getLIRforBlock(block)); } } } } - private class Mapper implements FrameMappable { - - public void map(FrameMappingTool tool) { - try (Scope scope = Debug.scope("StackSlotMappingLSRA")) { - for (Interval current : intervals) { - if (current != null) { - if (isVirtualStackSlot(current.location())) { - VirtualStackSlot value = asVirtualStackSlot(current.location()); - StackSlot stackSlot = tool.getStackSlot(value); - Debug.log("map %s -> %s", value, stackSlot); - current.assignLocation(stackSlot); - } - if (current.isSplitParent() && current.spillSlot() != null && isVirtualStackSlot(current.spillSlot())) { - VirtualStackSlot value = asVirtualStackSlot(current.spillSlot()); - StackSlot stackSlot = tool.getStackSlot(value); - Debug.log("map %s -> %s", value, stackSlot); - current.setSpillSlot(stackSlot); - } - } - } - } - } - - } - public static void allocate(TargetDescription target, LIRGenerationResult res) { new LinearScan(target, res).allocate(); } @@ -1892,16 +1796,6 @@ printIntervals("After register allocation"); printLir("After register allocation", true); - // register interval mapper - frameMapBuilder.requireMapping(new Mapper()); - - if (!LocationMarker.Options.UseLocationMarker.getValue()) { - // build frame map - res.buildFrameMap(); - } - - printLir("After FrameMap building", true); - sortIntervalsAfterAllocation(); if (DetailedAsserts.getValue()) { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java Sat Jan 31 19:03:33 2015 +0100 @@ -55,7 +55,11 @@ } public Set keySet() { - throw new UnsupportedOperationException("Cannot get key set from this map"); + HashSet entries = new HashSet<>(); + for (Map.Entry entry : entries()) { + entries.add(entry.getKey()); + } + return entries; } public Collection values() { @@ -69,7 +73,11 @@ return result; } - public Set> entrySet() { - throw new UnsupportedOperationException("Cannot get entry set for this map"); + public Set> entrySet() { + HashSet> entries = new HashSet<>(); + for (Map.Entry entry : entries()) { + entries.add(entry); + } + return entries; } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Sat Jan 31 19:03:33 2015 +0100 @@ -210,7 +210,7 @@ CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); // create suites everytime, as we modify options for the compiler final Suites suitesLocal = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().createSuites(); - final CompilationResult compResult = compileGraph(graph, null, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), + final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default); addMethod(method, compResult); } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Sat Jan 31 19:03:33 2015 +0100 @@ -197,7 +197,7 @@ HotSpotProviders providers = backend.getProviders(); BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess()); OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL; - result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default, optimisticOpts); + result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default, optimisticOpts, providers.getReplacements()); } else { Map graphCache = null; if (GraalOptions.CacheGraphs.getValue()) { @@ -230,7 +230,7 @@ // all code after the OSR loop is never executed. optimisticOpts.remove(Optimization.RemoveNeverExecutedCode); } - result = compileGraph(graph, null, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo, + result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo, method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default); } result.setId(getId()); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Sat Jan 31 19:03:33 2015 +0100 @@ -31,6 +31,7 @@ import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.java.*; import com.oracle.graal.nodes.spi.*; /** @@ -65,6 +66,15 @@ HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls(); final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer(); + try (InitTimer st = timer("graphBuilderPlugins.initialize")) { + GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous(); + GraphBuilderPlugins plugins = phase.getGraphBuilderPlugins(); + Iterable sl = Services.load(GraphBuilderPluginsProvider.class); + for (GraphBuilderPluginsProvider p : sl) { + p.registerPlugins(providers.getMetaAccess(), plugins); + } + } + try (InitTimer st = timer("foreignCalls.initialize")) { foreignCalls.initialize(providers, config); } @@ -92,6 +102,5 @@ throw Debug.handle(e); } } - } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Sat Jan 31 19:03:33 2015 +0100 @@ -66,7 +66,7 @@ } if (obj instanceof HotSpotResolvedJavaField) { HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; - if (that.offset != this.offset) { + if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; } else if (this.holder.equals(that.holder)) { assert this.name.equals(that.name) && this.type.equals(that.type); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Sat Jan 31 19:03:33 2015 +0100 @@ -30,7 +30,7 @@ import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.java.*; -import com.oracle.graal.java.GraphBuilderConfiguration.*; +import com.oracle.graal.java.GraphBuilderConfiguration.DebugInfoMode; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; @@ -84,7 +84,7 @@ protected PhaseSuite createGraphBuilderSuite() { PhaseSuite suite = new PhaseSuite<>(); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(); - config.setInlineTrivial(true); + config = config.withInlineTrivial(true); suite.appendPhase(new GraphBuilderPhase(config)); return suite; } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Sat Jan 31 19:03:33 2015 +0100 @@ -162,7 +162,7 @@ Suites suites = providers.getSuites().createSuites(); PhaseSuite phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false); - CompilationResult compResult = GraalCompiler.compileGraph(g, null, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL, + CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, new CompilationResult(), CompilationResultBuilderFactory.Default); InstalledCode installedCode; try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.hotspot.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; + +@ServiceProvider(GraphBuilderPluginsProvider.class) +public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { + public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + plugins.register(metaAccess, ObjectPlugin.class); + } + + enum ObjectPlugin implements GraphBuilderPlugin { + getClass() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + assert args.length == 1; + ValueNode rcvr = args[0]; + GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr)); + StampProvider stampProvider = builder.getStampProvider(); + LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi)); + HubGetClassNode mirror = builder.append(new HubGetClassNode(builder.getMetaAccess(), hub)); + builder.push(Kind.Object, mirror); + return true; + } + }; + + public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { + return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name()); + } + + @Override + public String toString() { + return Object.class.getName() + "." + name() + "()"; + } + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Sat Jan 31 19:03:33 2015 +0100 @@ -1153,5 +1153,4 @@ } Debug.log("%s", sb); } - } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.java; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +@ServiceProvider(GraphBuilderPluginsProvider.class) +public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { + public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + plugins.register(metaAccess, ObjectPlugin.class); + } + + enum ObjectPlugin implements GraphBuilderPlugin { + init() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + assert args.length == 1; + ValueNode rcvr = args[0]; + ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp(); + + boolean needsCheck = true; + if (objectStamp.isExactType()) { + needsCheck = objectStamp.type().hasFinalizer(); + } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { + // if either the declared type of receiver or the holder + // can be assumed to have no finalizers + Assumptions assumptions = builder.getAssumptions(); + if (assumptions.useOptimisticAssumptions()) { + assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type()); + needsCheck = false; + } + } + + if (needsCheck) { + builder.append(new RegisterFinalizerNode(rcvr)); + } + return true; + } + + public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { + return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, ""); + } + }; + + @Override + public String toString() { + return Object.class.getName() + "." + name() + "()"; + } + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Sat Jan 31 19:03:33 2015 +0100 @@ -36,7 +36,7 @@ private final ResolvedJavaType[] skippedExceptionTypes; private final DebugInfoMode debugInfoMode; private final boolean doLivenessAnalysis; - private boolean inlineTrivial; + private final boolean inlineTrivial; public static enum DebugInfoMode { SafePointsOnly, @@ -62,25 +62,35 @@ Full, } - protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis) { + protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis, + boolean inlineTrivial) { this.eagerResolving = eagerResolving; this.omitAllExceptionEdges = omitAllExceptionEdges; this.debugInfoMode = debugInfoMode; this.skippedExceptionTypes = skippedExceptionTypes; this.doLivenessAnalysis = doLivenessAnalysis; + this.inlineTrivial = inlineTrivial; } public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) { - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial); + } + + public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) { + return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, inlineTrivial); } public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial); } public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) { - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, inlineTrivial); + } + + public GraphBuilderConfiguration withInlineTrivial(boolean newInlineTrivial) { + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newInlineTrivial); } public ResolvedJavaType[] getSkippedExceptionTypes() { @@ -108,19 +118,19 @@ } public static GraphBuilderConfiguration getDefault() { - return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue()); + return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false); } public static GraphBuilderConfiguration getEagerDefault() { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue()); + return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false); } public static GraphBuilderConfiguration getSnippetDefault() { - return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue()); + return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false); } public static GraphBuilderConfiguration getFullDebugDefault() { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue()); + return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false); } /** @@ -135,8 +145,4 @@ public boolean shouldInlineTrivial() { return inlineTrivial; } - - public void setInlineTrivial(boolean inlineTrivial) { - this.inlineTrivial = inlineTrivial; - } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.java; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +/** + * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object. + */ +public interface GraphBuilderContext { + + T append(T fixed); + + T append(T fixed); + + T append(T fixed); + + T append(T v); + + StampProvider getStampProvider(); + + MetaAccessProvider getMetaAccess(); + + Assumptions getAssumptions(); + + void push(Kind kind, ValueNode value); +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sat Jan 31 19:03:33 2015 +0100 @@ -47,6 +47,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -58,20 +59,26 @@ public class GraphBuilderPhase extends BasePhase { private final GraphBuilderConfiguration graphBuilderConfig; + private final GraphBuilderPlugins graphBuilderPlugins; - public GraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfig) { - this.graphBuilderConfig = graphBuilderConfig; + public GraphBuilderPhase(GraphBuilderConfiguration config) { + this.graphBuilderConfig = config; + this.graphBuilderPlugins = new GraphBuilderPlugins(); } @Override protected void run(StructuredGraph graph, HighTierContext context) { - new Instance(context.getMetaAccess(), graphBuilderConfig, context.getOptimisticOptimizations()).run(graph); + new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), graphBuilderConfig, graphBuilderPlugins, context.getOptimisticOptimizations()).run(graph); } public GraphBuilderConfiguration getGraphBuilderConfig() { return graphBuilderConfig; } + public GraphBuilderPlugins getGraphBuilderPlugins() { + return graphBuilderPlugins; + } + public static class Instance extends Phase { protected StructuredGraph currentGraph; @@ -81,7 +88,10 @@ private ResolvedJavaMethod rootMethod; private final GraphBuilderConfiguration graphBuilderConfig; + private final GraphBuilderPlugins graphBuilderPlugins; private final OptimisticOptimizations optimisticOpts; + private final StampProvider stampProvider; + private final Assumptions assumptions; /** * Gets the graph being processed by this builder. @@ -90,13 +100,21 @@ return currentGraph; } - public Instance(MetaAccessProvider metaAccess, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, + OptimisticOptimizations optimisticOpts) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.metaAccess = metaAccess; + this.stampProvider = stampProvider; + this.assumptions = assumptions; + this.graphBuilderPlugins = graphBuilderPlugins; assert metaAccess != null; } + public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + this(metaAccess, stampProvider, assumptions, graphBuilderConfig, null, optimisticOpts); + } + @Override protected void run(StructuredGraph graph) { ResolvedJavaMethod method = graph.method(); @@ -143,7 +161,7 @@ } } - public class BytecodeParser extends AbstractBytecodeParser { + public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext { private BciBlock[] loopHeaders; private LocalLiveness liveness; @@ -752,38 +770,49 @@ args[0] = TypeProfileProxyNode.proxify(args[0], profile); } } + if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect()) { - if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect() && targetMethod.canBeInlined() && targetMethod.hasBytecodes()) { - if (targetMethod.getCode().length <= GraalOptions.TrivialInliningSize.getValue() && currentDepth < GraalOptions.InlineDuringParsingMaxDepth.getValue() && - graphBuilderConfig.shouldInlineTrivial()) { - BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, StructuredGraph.INVOCATION_ENTRY_BCI); - final FrameState[] lazyFrameState = new FrameState[1]; - HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, () -> { - if (lazyFrameState[0] == null) { - lazyFrameState[0] = frameState.create(bci()); - } - return lazyFrameState[0]; - }); - startFrameState.initializeFromArgumentsArray(args); - parser.build(currentDepth + 1, this.lastInstr, startFrameState); - - FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); - this.lastInstr = calleeBeforeReturnNode; - if (calleeBeforeReturnNode != null) { - ValueNode calleeReturnValue = parser.getReturnValue(); - if (calleeReturnValue != null) { - frameState.push(calleeReturnValue.getKind().getStackKind(), calleeReturnValue); + if (graphBuilderPlugins != null) { + GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod); + if (plugin != null) { + if (plugin.handleInvocation(this, args)) { + return; } } + } - FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); - if (calleeBeforeUnwindNode != null) { - ValueNode calleeUnwindValue = parser.getUnwindValue(); - assert calleeUnwindValue != null; - calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); + if (targetMethod.canBeInlined() && targetMethod.hasBytecodes()) { + if (targetMethod.getCode().length <= GraalOptions.TrivialInliningSize.getValue() && currentDepth < GraalOptions.InlineDuringParsingMaxDepth.getValue() && + graphBuilderConfig.shouldInlineTrivial()) { + BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, StructuredGraph.INVOCATION_ENTRY_BCI); + final FrameState[] lazyFrameState = new FrameState[1]; + HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, () -> { + if (lazyFrameState[0] == null) { + lazyFrameState[0] = frameState.create(bci()); + } + return lazyFrameState[0]; + }); + startFrameState.initializeFromArgumentsArray(args); + parser.build(currentDepth + 1, this.lastInstr, startFrameState); + + FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); + this.lastInstr = calleeBeforeReturnNode; + if (calleeBeforeReturnNode != null) { + ValueNode calleeReturnValue = parser.getReturnValue(); + if (calleeReturnValue != null) { + frameState.push(calleeReturnValue.getKind().getStackKind(), calleeReturnValue); + } + } + + FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); + if (calleeBeforeUnwindNode != null) { + ValueNode calleeUnwindValue = parser.getUnwindValue(); + assert calleeUnwindValue != null; + calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); + } + + return; } - - return; } } @@ -937,7 +966,7 @@ throw GraalInternalError.shouldNotReachHere("Can not append Node of type: " + v.getClass().getName()); } - private T append(T fixed) { + public T append(T fixed) { assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; T added = currentGraph.add(fixed); @@ -946,7 +975,7 @@ return added; } - private T append(T fixed) { + public T append(T fixed) { assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; T added = currentGraph.add(fixed); @@ -955,7 +984,7 @@ return added; } - protected T append(T fixed) { + public T append(T fixed) { assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; T added = currentGraph.add(fixed); @@ -964,7 +993,7 @@ return added; } - private T append(T v) { + public T append(T v) { assert !(v instanceof ConstantNode); T added = currentGraph.unique(v); return added; @@ -1456,6 +1485,22 @@ append(ifNode); } + public StampProvider getStampProvider() { + return stampProvider; + } + + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + public Assumptions getAssumptions() { + return assumptions; + } + + public void push(Kind kind, ValueNode value) { + frameState.push(kind, value); + } + } } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.java; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.nodes.*; + +/** + * Extensions for handling certain bytecode instructions while building a + * {@linkplain StructuredGraph graph} from a bytecode stream. + */ +public interface GraphBuilderPlugin { + + /** + * Processes an invocation parsed in a bytecode stream and add nodes to a graph being + * constructed that implement the semantics of the invocation. + * + * @param builder object being used to build a graph + * @param args the arguments to the invocation + */ + boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args); + + /** + * Gets the target method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} + * . + */ + ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess); + + static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class clazz, String methodName, Class... parameterTypes) { + try { + return metaAccess.lookupJavaMethod(methodName.equals("") ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getDeclaredMethod(methodName, parameterTypes)); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.java; + +import java.util.*; +import java.util.stream.*; + +import com.oracle.graal.api.meta.*; + +/** + * A repository of {@link GraphBuilderPlugin}s. + */ +public class GraphBuilderPlugins { + + private final Map map = new HashMap<>(); + + /** + * Registers all the constants of an enum that implements {@link GraphBuilderPlugin}. + */ + public & GraphBuilderPlugin> void register(MetaAccessProvider metaAccess, Class enumClass) { + assert Enum.class.isAssignableFrom(enumClass); + Object[] enumConstants = enumClass.getEnumConstants(); + for (Object o : enumConstants) { + GraphBuilderPlugin gbp = (GraphBuilderPlugin) o; + ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess); + GraphBuilderPlugin oldValue = map.put(target, gbp); + assert oldValue == null; + } + } + + /** + * Gets the plugin for a given method registered in the object. + * + * @param method the method to lookup + * @return the plugin associated with {@code method} or {@code null} if none exists + */ + public GraphBuilderPlugin getPlugin(ResolvedJavaMethod method) { + return map.get(method); + } + + @Override + public String toString() { + return map.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", ")); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.java; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; + +/** + * Interface for providers of {@link GraphBuilderPlugin}s. + */ +public interface GraphBuilderPluginsProvider extends Service { + /** + * Registers the plugins provided by this object with a plugins registry. + * + * @param plugins registry of plugins + */ + void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins); +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMapBuilder.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMapBuilder.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMapBuilder.java Sat Jan 31 19:03:33 2015 +0100 @@ -36,14 +36,14 @@ * runtime for walking/inspecting frames of such methods. */ public StackSlot allocateRBPSpillSlot() { - return ((AMD64FrameMap) frameMap).allocateRBPSpillSlot(); + return ((AMD64FrameMap) getFrameMap()).allocateRBPSpillSlot(); } public void freeRBPSpillSlot() { - ((AMD64FrameMap) frameMap).freeRBPSpillSlot(); + ((AMD64FrameMap) getFrameMap()).freeRBPSpillSlot(); } public StackSlot allocateDeoptimizationRescueSlot() { - return ((AMD64FrameMap) frameMap).allocateDeoptimizationRescueSlot(); + return ((AMD64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot(); } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMapBuilder.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMapBuilder.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMapBuilder.java Sat Jan 31 19:03:33 2015 +0100 @@ -32,6 +32,6 @@ } public StackSlot allocateDeoptimizationRescueSlot() { - return ((SPARCFrameMap) frameMap).allocateDeoptimizationRescueSlot(); + return ((SPARCFrameMap) getFrameMap()).allocateDeoptimizationRescueSlot(); } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Sat Jan 31 19:03:33 2015 +0100 @@ -22,24 +22,18 @@ */ package com.oracle.graal.lir; -import static com.oracle.graal.api.code.ValueUtil.*; - import java.util.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.StandardOp.LabelOp; -import com.oracle.graal.lir.framemap.*; /** * This class implements the overall container for the LIR graph and directs its construction, * optimization, and finalization. */ -public class LIR implements FrameMappable { +public class LIR { private final AbstractControlFlowGraph cfg; @@ -226,30 +220,4 @@ } } - public void map(FrameMappingTool tool) { - try (Scope scope = Debug.scope("StackSlotMappingLIR")) { - ValueProcedure updateProc = (value, mode, flags) -> { - if (isVirtualStackSlot(value)) { - StackSlot stackSlot = tool.getStackSlot(asVirtualStackSlot(value)); - Debug.log("map %s -> %s", value, stackSlot); - return stackSlot; - } - return value; - }; - for (AbstractBlock block : getControlFlowGraph().getBlocks()) { - try (Indent indent0 = Debug.logAndIndent("block: %s", block)) { - for (LIRInstruction inst : getLIRforBlock(block)) { - try (Indent indent1 = Debug.logAndIndent("Inst: %d: %s", inst.id(), inst)) { - inst.forEachAlive(updateProc); - inst.forEachInput(updateProc); - inst.forEachOutput(updateProc); - inst.forEachTemp(updateProc); - inst.forEachState(updateProc); - } - } - } - } - } - } - } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java Sat Jan 31 19:03:33 2015 +0100 @@ -256,7 +256,7 @@ * @param kind The kind of the spill slot to be reserved. * @return A spill slot denoting the reserved memory area. */ - protected StackSlot allocateSpillSlot(LIRKind kind) { + public StackSlot allocateSpillSlot(LIRKind kind) { assert frameSize == -1 : "frame size must not yet be fixed"; int size = spillSlotSize(kind); spillSize = NumUtil.roundUp(spillSize + size, size); @@ -264,6 +264,16 @@ } /** + * Returns the size of the stack slot range for {@code slots} objects. + * + * @param slots The number of slots. + * @return The size in byte + */ + public int spillSlotRangeSize(int slots) { + return slots * getTarget().wordSize; + } + + /** * Reserves a number of contiguous slots in the frame of the method being compiled. If the * requested number of slots is 0, this method returns {@code null}. * @@ -274,12 +284,12 @@ * collector could see garbage object values. * @return the first reserved stack slot (i.e., at the lowest address) */ - protected StackSlot allocateStackSlots(int slots, BitSet objects) { + public StackSlot allocateStackSlots(int slots, BitSet objects) { assert frameSize == -1 : "frame size must not yet be fixed"; if (slots == 0) { return null; } - spillSize += (slots * getTarget().wordSize); + spillSize += spillSlotRangeSize(slots); if (!objects.isEmpty()) { assert objects.length() <= slots; diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilder.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilder.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilder.java Sat Jan 31 19:03:33 2015 +0100 @@ -27,6 +27,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.stackslotalloc.*; /** * A {@link FrameMapBuilder} is used to collect all information necessary to @@ -72,14 +73,8 @@ void callsMethod(CallingConvention cc); /** - * Registers a FrameMappable class so that virtual stack slots can be changed to real stack - * slots. - */ - void requireMapping(FrameMappable mappable); - - /** * Creates a {@linkplain FrameMap} based on the information collected by this * {@linkplain FrameMapBuilder}. */ - FrameMap buildFrameMap(LIRGenerationResult result); + FrameMap buildFrameMap(LIRGenerationResult result, StackSlotAllocator allocator); } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java Sat Jan 31 19:03:33 2015 +0100 @@ -27,16 +27,19 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.stackslotalloc.*; /** * A FrameMapBuilder that records allocation. */ -public class FrameMapBuilderImpl implements FrameMapBuilder { +public class FrameMapBuilderImpl implements FrameMapBuilderTool { private final RegisterConfig registerConfig; private final CodeCacheProvider codeCache; - protected final FrameMap frameMap; + private final FrameMap frameMap; private final List stackSlots; private final List calls; private int numStackSlots; @@ -48,12 +51,9 @@ this.frameMap = frameMap; this.stackSlots = new ArrayList<>(); this.calls = new ArrayList<>(); - this.mappables = new ArrayList<>(); this.numStackSlots = 0; } - private final List mappables; - public VirtualStackSlot allocateSpillSlot(LIRKind kind) { SimpleVirtualStackSlot slot = new SimpleVirtualStackSlot(numStackSlots++, kind); stackSlots.add(slot); @@ -80,10 +80,10 @@ return codeCache; } - /** - * Returns the number of {@link VirtualStackSlot}s created by this {@link FrameMapBuilder}. Can - * be used as an upper bound for an array indexed by {@link VirtualStackSlot#getId()}. - */ + public FrameMap getFrameMap() { + return frameMap; + } + public int getNumberOfStackSlots() { return numStackSlots; } @@ -92,23 +92,18 @@ calls.add(cc); } - public FrameMap buildFrameMap(LIRGenerationResult res) { - FrameMappingTool mapper = new SimpleStackSlotAllocator().allocateStackSlots(this); + public FrameMap buildFrameMap(LIRGenerationResult res, StackSlotAllocator allocator) { + try (Scope s = Debug.scope("StackSlotAllocation")) { + allocator.allocateStackSlots(this, res); + } for (CallingConvention cc : calls) { frameMap.callsMethod(cc); } - // rewrite - mappables.forEach(m -> m.map(mapper)); - frameMap.finish(); return frameMap; } - public void requireMapping(FrameMappable mappable) { - this.mappables.add(mappable); - } - - List getStackSlots() { + public List getStackSlots() { return stackSlots; } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderTool.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 2014, 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 com.oracle.graal.lir.framemap; + +import java.util.*; + +import com.oracle.graal.api.code.*; + +/** + * A {@link FrameMapBuilder} that allows access to the underlying {@link FrameMap}. + */ +public interface FrameMapBuilderTool extends FrameMapBuilder { + + /** + * Returns the number of {@link VirtualStackSlot}s created by this {@link FrameMapBuilder}. Can + * be used as an upper bound for an array indexed by {@link VirtualStackSlot#getId()}. + */ + int getNumberOfStackSlots(); + + List getStackSlots(); + + FrameMap getFrameMap(); + +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappable.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappable.java Wed Jan 28 15:07:54 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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 com.oracle.graal.lir.framemap; - -/** - * This interface should be implemented by all classes that store virtual stack slots to convert - * them into real stack slots when {@link FrameMapBuilder#buildFrameMap} is called. Implementors - * should register themselves using {@link FrameMapBuilder#requireMapping(FrameMappable)}. - */ -public interface FrameMappable { - void map(FrameMappingTool tool); -} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappingTool.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappingTool.java Wed Jan 28 15:07:54 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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 com.oracle.graal.lir.framemap; - -import com.oracle.graal.api.code.*; - -/** - * A tool to get the real stack slot from a virtual stack slot. - */ -@FunctionalInterface -public interface FrameMappingTool { - StackSlot getStackSlot(VirtualStackSlot slot); -} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleStackSlotAllocator.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleStackSlotAllocator.java Wed Jan 28 15:07:54 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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 com.oracle.graal.lir.framemap; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.common.*; - -public class SimpleStackSlotAllocator implements StackSlotAllocator { - - public FrameMappingTool allocateStackSlots(FrameMapBuilderImpl builder) { - StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()]; - for (VirtualStackSlot virtualSlot : builder.getStackSlots()) { - final StackSlot slot; - if (virtualSlot instanceof SimpleVirtualStackSlot) { - slot = mapSimpleVirtualStackSlot(builder, (SimpleVirtualStackSlot) virtualSlot); - } else if (virtualSlot instanceof VirtualStackSlotRange) { - slot = mapVirtualStackSlotRange(builder, (VirtualStackSlotRange) virtualSlot); - } else { - throw GraalInternalError.shouldNotReachHere("Unknown VirtualStackSlot: " + virtualSlot); - } - mapping[virtualSlot.getId()] = slot; - } - return v -> mapping[v.getId()]; - } - - protected StackSlot mapSimpleVirtualStackSlot(FrameMapBuilderImpl builder, SimpleVirtualStackSlot virtualStackSlot) { - return builder.frameMap.allocateSpillSlot(virtualStackSlot.getLIRKind()); - } - - protected StackSlot mapVirtualStackSlotRange(FrameMapBuilderImpl builder, VirtualStackSlotRange virtualStackSlot) { - return builder.frameMap.allocateStackSlots(virtualStackSlot.getSlots(), virtualStackSlot.getObjects()); - } -} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java Sat Jan 31 19:03:33 2015 +0100 @@ -28,7 +28,7 @@ /** * Represents a {@link VirtualStackSlot virtual stack slot} for a specific {@link LIRKind kind}. */ -class SimpleVirtualStackSlot extends VirtualStackSlot { +public class SimpleVirtualStackSlot extends VirtualStackSlot { private static final long serialVersionUID = 7654295701165421750L; diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/StackSlotAllocator.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/StackSlotAllocator.java Wed Jan 28 15:07:54 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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 com.oracle.graal.lir.framemap; - -import com.oracle.graal.api.code.*; - -/** - * A {@link StackSlotAllocator} is responsible for translating {@link VirtualStackSlot virtual} - * stack slots into {@link StackSlot real} stack slots. - */ -public interface StackSlotAllocator { - FrameMappingTool allocateStackSlots(FrameMapBuilderImpl builder); -} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java Sat Jan 31 19:03:33 2015 +0100 @@ -31,7 +31,7 @@ * Represents a {@link #getSlots() numbered} range of {@link VirtualStackSlot virtual stack slot} of * size {@link TargetDescription#wordSize}. */ -class VirtualStackSlotRange extends VirtualStackSlot { +public class VirtualStackSlotRange extends VirtualStackSlot { private static final long serialVersionUID = 5152592950118317121L; private final BitSet objects; diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java Sat Jan 31 19:03:33 2015 +0100 @@ -24,6 +24,7 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.stackslotalloc.*; public interface LIRGenerationResult { @@ -31,7 +32,7 @@ * Returns the {@link FrameMapBuilder} for collecting the information to build a * {@link FrameMap}. * - * This method can only be used prior calling {@link #buildFrameMap()}. + * This method can only be used prior calling {@link #buildFrameMap}. */ FrameMapBuilder getFrameMapBuilder(); @@ -41,12 +42,12 @@ * * @see FrameMapBuilder#buildFrameMap */ - void buildFrameMap(); + void buildFrameMap(StackSlotAllocator allocator); /** * Returns the {@link FrameMap} associated with this {@link LIRGenerationResult}. * - * This method can only be called after {@link #buildFrameMap()}. + * This method can only be called after {@link #buildFrameMap}. */ FrameMap getFrameMap(); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java Sat Jan 31 19:03:33 2015 +0100 @@ -24,6 +24,7 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.stackslotalloc.*; public class LIRGenerationResultBase implements LIRGenerationResult { private final LIR lir; @@ -59,9 +60,9 @@ return frameMapBuilder; } - public void buildFrameMap() { + public void buildFrameMap(StackSlotAllocator allocator) { assert frameMap == null : "buildFrameMap() can only be called once!"; - frameMap = frameMapBuilder.buildFrameMap(this); + frameMap = frameMapBuilder.buildFrameMap(this, allocator); } public FrameMap getFrameMap() { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.lir.stackslotalloc; + +import static com.oracle.graal.api.code.CodeUtil.*; + +import java.util.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; + +public class InstructionNumberer { + + private LIRInstruction[] opIdToInstructionMap; + private AbstractBlock[] opIdToBlockMap; + + /** + * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR + * instructions in a method have an index one greater than their linear-scan order predecesor + * with the first instruction having an index of 0. + */ + private static int opIdToIndex(int opId) { + return opId >> 1; + } + + /** + * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}. + * + * @param opId an instruction {@linkplain LIRInstruction#id id} + * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} + */ + protected LIRInstruction instructionForId(int opId) { + assert isEven(opId) : "opId not even"; + LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)]; + assert instr.id() == opId; + return instr; + } + + /** + * Numbers all instructions in all blocks. + */ + protected void numberInstructions(LIR lir, List> sortedBlocks) { + + // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. + int numInstructions = 0; + for (AbstractBlock block : sortedBlocks) { + numInstructions += lir.getLIRforBlock(block).size(); + } + + // initialize with correct length + opIdToInstructionMap = new LIRInstruction[numInstructions]; + opIdToBlockMap = new AbstractBlock[numInstructions]; + + int opId = 0; + int index = 0; + for (AbstractBlock block : sortedBlocks) { + + List instructions = lir.getLIRforBlock(block); + + int numInst = instructions.size(); + for (int j = 0; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + op.setId(opId); + + opIdToInstructionMap[index] = op; + opIdToBlockMap[index] = block; + assert instructionForId(opId) == op : "must match"; + + index++; + opId += 2; // numbering of lirOps by two + } + } + assert index == numInstructions : "must match"; + assert (index << 1) == opId : "must match: " + (index << 1); + } + + /** + * Gets the highest instruction id allocated by this object. + */ + public int maxOpId() { + assert opIdToInstructionMap.length > 0 : "no operations"; + return (opIdToInstructionMap.length - 1) << 1; + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.lir.stackslotalloc; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import java.util.*; +import java.util.function.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.options.*; + +/** + * Linear Scan {@link StackSlotAllocator}. + *

+ * Remark: The analysis works under the assumption that a stack slot is no longer live after + * its last usage. If an {@link LIRInstruction instruction} transfers the raw address of the stack + * slot to another location, e.g. a registers, and this location is referenced later on, the + * {@link com.oracle.graal.lir.LIRInstruction.Use usage} of the stack slot must be marked with the + * {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content + * destroyed. + */ +public final class LSStackSlotAllocator implements StackSlotAllocator { + + public static class Options { + // @formatter:off + @Option(help = "Enable linear scan stack slot allocation.", type = OptionType.Debug) + public static final OptionValue EnableLSStackSlotAllocation = new OptionValue<>(true); + // @formatter:on + } + + /** + * The number of allocated stack slots. + */ + static final DebugMetric uninitializedSlots = Debug.metric("StackSlotAllocator[uninitializedSlots]"); + + public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) { + new Allocator(res.getLIR(), builder).allocate(); + } + + static final class Allocator extends InstructionNumberer { + private final LIR lir; + private final FrameMapBuilderTool frameMapBuilder; + private final StackInterval[] stackSlotMap; + private LinkedList unhandled; + private LinkedList active; + + private List> sortedBlocks; + + private Allocator(LIR lir, FrameMapBuilderTool frameMapBuilder) { + this.lir = lir; + this.frameMapBuilder = frameMapBuilder; + this.stackSlotMap = new StackInterval[frameMapBuilder.getNumberOfStackSlots()]; + } + + private void allocate() { + // create block ordering + List> blocks = lir.getControlFlowGraph().getBlocks(); + assert blocks.size() > 0; + + sortedBlocks = lir.getControlFlowGraph().getBlocks(); + numberInstructions(lir, sortedBlocks); + Debug.dump(lir, "After StackSlot numbering"); + + long currentFrameSize = Debug.isMeterEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0; + // build intervals + // buildIntervals(); + try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals")) { + buildIntervalsSlow(); + } + if (Debug.isEnabled()) { + verifyIntervals(); + } + if (Debug.isDumpEnabled()) { + dumpIntervals("Before stack slot allocation"); + } + // allocate stack slots + allocateStackSlots(); + if (Debug.isDumpEnabled()) { + dumpIntervals("After stack slot allocation"); + } + + // assign stack slots + assignStackSlots(); + Debug.dump(lir, "After StackSlot assignment"); + StackSlotAllocator.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize); + } + + private void buildIntervalsSlow() { + new SlowIntervalBuilder().build(); + } + + /** + * Calculates the stack intervals using a worklist-based backwards data-flow analysis. + */ + private final class SlowIntervalBuilder { + final BlockMap liveInMap; + final BlockMap liveOutMap; + + private SlowIntervalBuilder() { + liveInMap = new BlockMap<>(lir.getControlFlowGraph()); + liveOutMap = new BlockMap<>(lir.getControlFlowGraph()); + } + + private void build() { + Deque> worklist = new ArrayDeque<>(); + for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) { + worklist.add(lir.getControlFlowGraph().getBlocks().get(i)); + } + for (AbstractBlock block : lir.getControlFlowGraph().getBlocks()) { + liveInMap.put(block, new BitSet(frameMapBuilder.getNumberOfStackSlots())); + } + while (!worklist.isEmpty()) { + AbstractBlock block = worklist.poll(); + processBlock(block, worklist); + } + } + + /** + * Merge outSet with in-set of successors. + */ + private boolean updateOutBlock(AbstractBlock block) { + BitSet union = new BitSet(frameMapBuilder.getNumberOfStackSlots()); + block.getSuccessors().forEach(succ -> union.or(liveInMap.get(succ))); + BitSet outSet = liveOutMap.get(block); + // check if changed + if (outSet == null || !union.equals(outSet)) { + liveOutMap.put(block, union); + return true; + } + return false; + } + + private void processBlock(AbstractBlock block, Deque> worklist) { + if (updateOutBlock(block)) { + try (Indent indent = Debug.logAndIndent("handle block %s", block)) { + List instructions = lir.getLIRforBlock(block); + // get out set and mark intervals + BitSet outSet = liveOutMap.get(block); + markOutInterval(outSet, getBlockEnd(instructions)); + printLiveSet("liveOut", outSet); + + // process instructions + BlockClosure closure = new BlockClosure((BitSet) outSet.clone()); + for (int i = instructions.size() - 1; i >= 0; i--) { + LIRInstruction inst = instructions.get(i); + closure.processInstructionBottomUp(inst); + } + + // add predecessors to work list + worklist.addAll(block.getPredecessors()); + // set in set and mark intervals + BitSet inSet = closure.getCurrentSet(); + liveInMap.put(block, inSet); + markInInterval(inSet, getBlockBegin(instructions)); + printLiveSet("liveIn", inSet); + } + } + } + + private void printLiveSet(String label, BitSet liveSet) { + if (Debug.isLogEnabled()) { + try (Indent indent = Debug.logAndIndent(label)) { + Debug.log("%s", liveSetToString(liveSet)); + } + } + } + + private String liveSetToString(BitSet liveSet) { + StringBuilder sb = new StringBuilder(); + for (int i = liveSet.nextSetBit(0); i >= 0; i = liveSet.nextSetBit(i + 1)) { + StackInterval interval = getIntervalFromStackId(i); + sb.append(interval.getOperand()).append(" "); + } + return sb.toString(); + } + + protected void markOutInterval(BitSet outSet, int blockEndOpId) { + for (int i = outSet.nextSetBit(0); i >= 0; i = outSet.nextSetBit(i + 1)) { + StackInterval interval = getIntervalFromStackId(i); + Debug.log("mark live operand: %s", interval.getOperand()); + interval.addTo(blockEndOpId); + } + } + + protected void markInInterval(BitSet inSet, int blockFirstOpId) { + for (int i = inSet.nextSetBit(0); i >= 0; i = inSet.nextSetBit(i + 1)) { + StackInterval interval = getIntervalFromStackId(i); + Debug.log("mark live operand: %s", interval.getOperand()); + interval.addFrom(blockFirstOpId); + } + } + + private final class BlockClosure { + private final BitSet currentSet; + + private BlockClosure(BitSet set) { + currentSet = set; + } + + private BitSet getCurrentSet() { + return currentSet; + } + + /** + * Process all values of an instruction bottom-up, i.e. definitions before usages. + * Values that start or end at the current operation are not included. + */ + private void processInstructionBottomUp(LIRInstruction op) { + try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) { + // kills + op.visitEachTemp(this::defConsumer); + op.visitEachOutput(this::defConsumer); + // forEachDestroyedCallerSavedRegister(op, this::defConsumer); + + // gen - values that are considered alive for this state + op.visitEachAlive(this::useConsumer); + op.visitEachState(this::useConsumer); + // mark locations + // gen + op.visitEachInput(this::useConsumer); + } + } + + /** + * @see InstructionValueConsumer + * + * @param inst + * @param operand + * @param mode + * @param flags + */ + private void useConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet flags) { + if (isVirtualStackSlot(operand)) { + VirtualStackSlot vslot = asVirtualStackSlot(operand); + addUse(vslot, inst, flags); + Debug.log("set operand: %s", operand); + currentSet.set(vslot.getId()); + } + } + + /** + * + * @see InstructionValueConsumer + * + * @param inst + * @param operand + * @param mode + * @param flags + */ + private void defConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet flags) { + if (isVirtualStackSlot(operand)) { + VirtualStackSlot vslot = asVirtualStackSlot(operand); + addDef(vslot, inst); + Debug.log("clear operand: %s", operand); + currentSet.clear(vslot.getId()); + } + + } + + private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet flags) { + StackInterval interval = getOrCreateInterval(stackSlot); + if (flags.contains(OperandFlag.UNINITIALIZED)) { + // Stack slot is marked uninitialized so we have to assume it is live all + // the time. + if (Debug.isMeterEnabled() && !(interval.from() == 0 && interval.to() == maxOpId())) { + uninitializedSlots.increment(); + } + interval.addDef(0); + interval.addUse(maxOpId()); + } else { + interval.addUse(inst.id()); + } + } + + private void addDef(VirtualStackSlot stackSlot, LIRInstruction inst) { + StackInterval interval = getOrCreateInterval(stackSlot); + interval.addDef(inst.id()); + } + + } + } + + private static int getBlockBegin(List instructions) { + return instructions.get(0).id(); + } + + private static int getBlockEnd(List instructions) { + return instructions.get(instructions.size() - 1).id() + 1; + } + + private StackInterval getOrCreateInterval(VirtualStackSlot stackSlot) { + StackInterval interval = get(stackSlot); + if (interval == null) { + interval = new StackInterval(stackSlot, stackSlot.getLIRKind()); + put(stackSlot, interval); + } + return interval; + } + + private StackInterval get(VirtualStackSlot stackSlot) { + return stackSlotMap[stackSlot.getId()]; + } + + private StackInterval getIntervalFromStackId(int id) { + return stackSlotMap[id]; + } + + private void put(VirtualStackSlot stackSlot, StackInterval interval) { + stackSlotMap[stackSlot.getId()] = interval; + } + + private void verifyIntervals() { + forEachInterval(interval -> { + assert interval.verify(this); + }); + } + + private void forEachInterval(Consumer proc) { + for (StackInterval interval : stackSlotMap) { + if (interval != null) { + proc.accept(interval); + } + } + } + + public void dumpIntervals(String label) { + Debug.dump(stackSlotMap, label); + } + + private void createUnhandled() { + unhandled = new LinkedList<>(); + active = new LinkedList<>(); + forEachInterval(this::insertSortedByFrom); + } + + private void insertSortedByFrom(StackInterval interval) { + unhandled.add(interval); + unhandled.sort((a, b) -> a.from() - b.from()); + } + + private void insertSortedByTo(StackInterval interval) { + active.add(interval); + active.sort((a, b) -> a.to() - b.to()); + } + + private void allocateStackSlots() { + // create interval lists + createUnhandled(); + + for (StackInterval current = activateNext(); current != null; current = activateNext()) { + try (Indent indent = Debug.logAndIndent("allocate %s", current)) { + allocateSlot(current); + } + } + + } + + private void allocateSlot(StackInterval current) { + VirtualStackSlot virtualSlot = current.getOperand(); + final StackSlot location; + if (virtualSlot instanceof VirtualStackSlotRange) { + // No reuse of ranges (yet). + VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot; + location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots(), slotRange.getObjects()); + StackSlotAllocator.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots())); + StackSlotAllocator.allocatedSlots.increment(); + } else { + assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpexted VirtualStackSlot type: " + virtualSlot; + StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot); + if (slot != null) { + /* + * Free stack slot available. Note that we create a new one because the kind + * might not match. + */ + location = StackSlot.get(current.kind(), slot.getRawOffset(), slot.getRawAddFrameSize()); + StackSlotAllocator.reusedSlots.increment(); + Debug.log(1, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot); + } else { + // Allocate new stack slot. + location = frameMapBuilder.getFrameMap().allocateSpillSlot(virtualSlot.getLIRKind()); + StackSlotAllocator.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotSize(virtualSlot.getLIRKind())); + StackSlotAllocator.allocatedSlots.increment(); + Debug.log(1, "New stack slot %s for virtual stack slot %s", location, virtualSlot); + } + } + Debug.log("Allocate location %s for interval %s", location, current); + current.setLocation(location); + } + + private static enum SlotSize { + Size1, + Size2, + Size4, + Size8, + Illegal; + } + + private SlotSize forKind(LIRKind kind) { + switch (frameMapBuilder.getFrameMap().spillSlotSize(kind)) { + case 1: + return SlotSize.Size1; + case 2: + return SlotSize.Size2; + case 4: + return SlotSize.Size4; + case 8: + return SlotSize.Size8; + default: + return SlotSize.Illegal; + } + } + + private EnumMap> freeSlots = new EnumMap<>(SlotSize.class); + + private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) { + assert slot != null; + SlotSize size = forKind(slot.getLIRKind()); + LinkedList freeList = size == SlotSize.Illegal ? null : freeSlots.get(size); + if (freeList == null) { + return null; + } + return freeList.pollFirst(); + } + + private void freeSlot(StackSlot slot) { + SlotSize size = forKind(slot.getLIRKind()); + if (size == SlotSize.Illegal) { + return; + } + LinkedList freeList = freeSlots.get(size); + if (freeList == null) { + freeList = new LinkedList<>(); + freeSlots.put(size, freeList); + } + freeList.add(slot); + } + + private StackInterval activateNext() { + if (unhandled.isEmpty()) { + return null; + } + StackInterval next = unhandled.pollFirst(); + for (int id = next.from(); activePeekId() < id;) { + finished(active.pollFirst()); + } + Debug.log("activte %s", next); + insertSortedByTo(next); + return next; + } + + private int activePeekId() { + StackInterval first = active.peekFirst(); + if (first == null) { + return Integer.MAX_VALUE; + } + return first.to(); + } + + private void finished(StackInterval interval) { + StackSlot location = interval.location(); + Debug.log("finished %s (freeing %s)", interval, location); + freeSlot(location); + } + + private void assignStackSlots() { + for (AbstractBlock block : sortedBlocks) { + lir.getLIRforBlock(block).forEach(op -> { + op.forEachInput(this::assignSlot); + op.forEachAlive(this::assignSlot); + op.forEachState(this::assignSlot); + + op.forEachTemp(this::assignSlot); + op.forEachOutput(this::assignSlot); + }); + } + } + + /** + * @see ValueProcedure + * @param value + * @param mode + * @param flags + */ + private Value assignSlot(Value value, OperandMode mode, EnumSet flags) { + if (isVirtualStackSlot(value)) { + VirtualStackSlot slot = asVirtualStackSlot(value); + StackInterval interval = get(slot); + assert interval != null; + return interval.location(); + } + return value; + } + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.lir.stackslotalloc; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; + +public class SimpleStackSlotAllocator implements StackSlotAllocator { + + public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) { + StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()]; + long currentFrameSize = Debug.isMeterEnabled() ? builder.getFrameMap().currentFrameSize() : 0; + for (VirtualStackSlot virtualSlot : builder.getStackSlots()) { + final StackSlot slot; + if (virtualSlot instanceof SimpleVirtualStackSlot) { + slot = mapSimpleVirtualStackSlot(builder, (SimpleVirtualStackSlot) virtualSlot); + virtualFramesize.add(builder.getFrameMap().spillSlotSize(virtualSlot.getLIRKind())); + } else if (virtualSlot instanceof VirtualStackSlotRange) { + VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot; + slot = mapVirtualStackSlotRange(builder, slotRange); + virtualFramesize.add(builder.getFrameMap().spillSlotRangeSize(slotRange.getSlots())); + } else { + throw GraalInternalError.shouldNotReachHere("Unknown VirtualStackSlot: " + virtualSlot); + } + allocatedSlots.increment(); + mapping[virtualSlot.getId()] = slot; + } + updateLIR(res, mapping); + allocatedFramesize.add(builder.getFrameMap().currentFrameSize() - currentFrameSize); + } + + protected void updateLIR(LIRGenerationResult res, StackSlot[] mapping) { + try (Scope scope = Debug.scope("StackSlotMappingLIR")) { + ValueProcedure updateProc = (value, mode, flags) -> { + if (isVirtualStackSlot(value)) { + StackSlot stackSlot = mapping[asVirtualStackSlot(value).getId()]; + Debug.log("map %s -> %s", value, stackSlot); + return stackSlot; + } + return value; + }; + for (AbstractBlock block : res.getLIR().getControlFlowGraph().getBlocks()) { + try (Indent indent0 = Debug.logAndIndent("block: %s", block)) { + for (LIRInstruction inst : res.getLIR().getLIRforBlock(block)) { + try (Indent indent1 = Debug.logAndIndent("Inst: %d: %s", inst.id(), inst)) { + inst.forEachAlive(updateProc); + inst.forEachInput(updateProc); + inst.forEachOutput(updateProc); + inst.forEachTemp(updateProc); + inst.forEachState(updateProc); + } + } + } + } + } + } + + protected StackSlot mapSimpleVirtualStackSlot(FrameMapBuilderTool builder, SimpleVirtualStackSlot virtualStackSlot) { + return builder.getFrameMap().allocateSpillSlot(virtualStackSlot.getLIRKind()); + } + + protected StackSlot mapVirtualStackSlotRange(FrameMapBuilderTool builder, VirtualStackSlotRange virtualStackSlot) { + return builder.getFrameMap().allocateStackSlots(virtualStackSlot.getSlots(), virtualStackSlot.getObjects()); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.lir.stackslotalloc; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; + +public class StackInterval { + + private static final int INVALID_START = Integer.MAX_VALUE; + private static final int INVALID_END = Integer.MIN_VALUE; + private final VirtualStackSlot operand; + private final LIRKind kind; + private int from = INVALID_START; + private int to = INVALID_END; + private final StackUsePosList usePos; + private StackSlot location; + + public enum UseType { + // Prefixes for c1viz + M_USE, + S_DEF + } + + public StackInterval(VirtualStackSlot operand, LIRKind kind) { + this.operand = operand; + this.kind = kind; + this.usePos = new StackUsePosList(); + } + + public boolean verify(LSStackSlotAllocator.Allocator allocator) { + assert usePosList().verify(); + // maxOpId + 1 it the last position in the last block (i.e. the "write position") + assert from >= 0 && to <= allocator.maxOpId() + 1 : String.format("from %d, to %d, maxOpId %d", from, to, allocator.maxOpId()); + return true; + } + + public VirtualStackSlot getOperand() { + return operand; + } + + public void addUse(int opId) { + addTo(opId); + Debug.log("Adding use pos: %d", opId); + usePos.add(opId, UseType.M_USE); + } + + public void addDef(int opId) { + addFrom(opId); + Debug.log("Adding def pos: %d", opId); + usePos.add(opId, UseType.S_DEF); + } + + public void addTo(int opId) { + if (opId >= to) { + to = opId; + } + } + + protected void addFrom(int opId) { + if (from > opId) { + from = opId; + // set opId also as to if it has not yet been set + if (to == INVALID_END) { + to = opId; + } + } + } + + public LIRKind kind() { + return kind; + } + + public StackSlot location() { + return location; + } + + public void setLocation(StackSlot location) { + this.location = location; + } + + public StackInterval locationHint() { + return null; + } + + public int from() { + return from; + } + + public int to() { + return to; + } + + public StackUsePosList usePosList() { + return usePos; + } + + public void fixFrom() { + if (from == INVALID_START) { + from = 0; + } + } + + public boolean isFixed() { + return from == 0; + } + + @Override + public String toString() { + return String.format("SI[%d-%d] k=%s o=%s l=%s", from, to, kind, operand, location); + } + +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackSlotAllocator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackSlotAllocator.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.lir.stackslotalloc; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; + +/** + * A {@link StackSlotAllocator} is responsible for translating {@link VirtualStackSlot virtual} + * stack slots into {@link StackSlot real} stack slots. This includes changing all occurrences of + * {@link VirtualStackSlot} in the {@link LIRGenerationResult#getLIR() LIR} to {@link StackSlot}. + */ +public interface StackSlotAllocator { + /** + * The number of allocated stack slots. + */ + DebugMetric allocatedSlots = Debug.metric("StackSlotAllocator[allocatedSlots]"); + /** + * The number of reused stack slots. + */ + DebugMetric reusedSlots = Debug.metric("StackSlotAllocator[reusedSlots]"); + /** + * The size (in bytes) required for all allocated stack slots. Note that this number corresponds + * to the actual frame size and might include alignment. + */ + DebugMetric allocatedFramesize = Debug.metric("StackSlotAllocator[AllocatedFramesize]"); + /** The size (in bytes) required for all virtual stack slots. */ + DebugMetric virtualFramesize = Debug.metric("StackSlotAllocator[VirtualFramesize]"); + + void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res); +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.lir.stackslotalloc; + +import java.util.*; + +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.lir.stackslotalloc.StackInterval.*; + +public class StackUsePosList { + + LinkedList usePosList; + LinkedList typeList; + + StackUsePosList() { + this.usePosList = new LinkedList<>(); + this.typeList = new LinkedList<>(); + } + + public int size() { + return usePosList.size(); + } + + public int usePos(int i) { + return usePosList.get(i); + } + + public void add(int opId, UseType type) { + if (usePosList.isEmpty() || opId <= usePosList.getLast()) { + usePosList.add(opId); + typeList.add(type); + } else if (opId >= usePosList.getFirst()) { + usePosList.addFirst(opId); + typeList.addFirst(type); + } else { + int size = usePosList.size(); + + assert size >= 2 : "Should be handled by the cases above"; + assert size == typeList.size() : "types and use pos out of sync"; + + ListIterator posIt = usePosList.listIterator(size - 1); + ListIterator typeIt = typeList.listIterator(size - 1); + + // we start with size-2 because we know it will not inserted at the end + while (posIt.hasPrevious()) { + assert posIt.nextIndex() == typeIt.nextIndex(); + int current = posIt.previous(); + + if (current >= opId) { + posIt.next(); + posIt.add(opId); + typeIt.add(type); + assert verify(); + return; + } + typeIt.previous(); + } + GraalInternalError.shouldNotReachHere(String.format("Unable to insert %d into %s", opId, usePosList)); + } + } + + public UseType getType(int i) { + return typeList.get(i); + } + + @Override + public String toString() { + return usePosList.toString() + System.lineSeparator() + typeList.toString(); + } + + public boolean verify() { + int prev = -1; + for (int i = usePosList.size() - 1; i >= 0; --i) { + int current = usePosList.get(i); + assert prev <= current : String.format("use positions not sorted: %d after %d", current, prev); + prev = current; + } + return true; + } + +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java Sat Jan 31 19:03:33 2015 +0100 @@ -74,6 +74,13 @@ if (loop.isOutsideLoop(op)) { continue; } + if (op.usages().count() == 1 && op.usages().first() == baseIvNode) { + /* + * This is just the base induction variable increment with no other uses so + * don't bother reporting it. + */ + continue; + } InductionVariable iv = null; ValueNode offset = addSub(op, baseIvNode); ValueNode scale; diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Sat Jan 31 19:03:33 2015 +0100 @@ -70,13 +70,13 @@ @Override public void lower(LoweringTool tool) { /* - * Don't allow guards with action None to float. In cases where 2 guards are testing - * equivalent conditions they might be lowered at the same location. If the guard with the - * None action is lowered before the the other guard then the code will be stuck repeatedly - * deoptimizing without invalidating the code. Conditional elimination will eliminate the - * guard if it's truly redundant in this case. + * Don't allow guards with action None and reason RuntimeConstraint to float. In cases where + * 2 guards are testing equivalent conditions they might be lowered at the same location. If + * the guard with the None action is lowered before the the other guard then the code will + * be stuck repeatedly deoptimizing without invalidating the code. Conditional elimination + * will eliminate the guard if it's truly redundant in this case. */ - if (graph().getGuardsStage().allowsFloatingGuards() && getAction() != DeoptimizationAction.None) { + if (graph().getGuardsStage().allowsFloatingGuards() && (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint)) { ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode(); this.replaceAtUsages(guard); ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode())); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.nodes.debug; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This node prevents control flow optimizations. It is never duplicated or merged with other + * control flow anchors. + */ +@NodeInfo +public class ControlFlowAnchorNode extends FixedWithNextNode implements LIRLowerable { + + private static class Unique { + } + + protected Unique unique; + + public ControlFlowAnchorNode(@SuppressWarnings("unused") Invoke invoke) { + super(StampFactory.forVoid()); + this.unique = new Unique(); + } + + public void generate(NodeLIRBuilderTool generator) { + // do nothing + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Sat Jan 31 19:03:33 2015 +0100 @@ -37,6 +37,7 @@ import com.oracle.graal.java.*; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.stackslotalloc.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -560,6 +561,46 @@ out.println(); } + public void printStackIntervals(String label, StackInterval[] intervals) { + begin("intervals"); + out.println(String.format("name \"%s\"", label)); + + for (StackInterval interval : intervals) { + if (interval != null) { + printStackInterval(interval); + } + } + + end("intervals"); + } + + private void printStackInterval(StackInterval interval) { + out.printf("%s %s ", interval.getOperand(), interval.isFixed() ? "fixed" : interval.kind().getPlatformKind()); + if (interval.location() != null) { + out.printf("\"[%s|%c]\"", interval.location(), interval.location().getKind().getTypeChar()); + } else { + out.printf("\"[%s|%c]\"", interval.getOperand(), interval.getOperand().getKind().getTypeChar()); + } + + StackInterval hint = interval.locationHint(); + out.printf("%s %s ", interval.getOperand(), hint != null ? hint.getOperand() : -1); + + out.printf("[%d, %d[", interval.from(), interval.to()); + + // print use positions + int prev = -1; + StackUsePosList usePosList = interval.usePosList(); + for (int i = usePosList.size() - 1; i >= 0; --i) { + assert prev <= usePosList.usePos(i) : "use positions not sorted"; + out.printf("%d %s ", usePosList.usePos(i), usePosList.getType(i)); + prev = usePosList.usePos(i); + } + + // print spill state + out.printf(" \"%s\"", "NOT_SUPPORTED"); + out.println(); + } + public void printSchedule(String message, SchedulePhase theSchedule) { schedule = theSchedule; cfg = schedule.getCFG(); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Sat Jan 31 19:03:33 2015 +0100 @@ -35,6 +35,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.java.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.stackslotalloc.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.phases.schedule.*; @@ -181,7 +182,8 @@ cfgPrinter.printMachineCode(codeCache.disassemble((CompilationResult) tuple[0], (InstalledCode) tuple[1]), message); } else if (object instanceof Interval[]) { cfgPrinter.printIntervals(message, (Interval[]) object); - + } else if (object instanceof StackInterval[]) { + cfgPrinter.printStackIntervals(message, (StackInterval[]) object); } cfgPrinter.target = null; diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java --- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java Sat Jan 31 19:03:33 2015 +0100 @@ -23,6 +23,8 @@ package com.oracle.graal.replacements.verifier; import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; import javax.annotation.processing.*; import javax.lang.model.element.*; @@ -46,6 +48,14 @@ if (value == null) { return null; } + if (expectedType.isArray()) { + ArrayList result = new ArrayList<>(); + List l = (List) value.getValue(); + for (AnnotationValue el : l) { + result.add(resolveAnnotationValue(expectedType.getComponentType(), el)); + } + return (T) result.toArray((Object[]) Array.newInstance(expectedType.getComponentType(), result.size())); + } Object unboxedValue = value.getValue(); if (unboxedValue != null) { if (expectedType == TypeMirror.class && unboxedValue instanceof String) { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java --- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java Sat Jan 31 19:03:33 2015 +0100 @@ -36,7 +36,6 @@ private static final String TYPE_VALUE = "value"; private static final String STRING_VALUE = "className"; private static final String OPTIONAL = "optional"; - private static final String STRING_VALUE_DEFAULT = ""; public ClassSubstitutionVerifier(ProcessingEnvironment env) { super(env); @@ -69,7 +68,7 @@ assert typeValue != null && stringValue != null && optionalValue != null; TypeMirror type = resolveAnnotationValue(TypeMirror.class, typeValue); - String className = resolveAnnotationValue(String.class, stringValue); + String[] classNames = resolveAnnotationValue(String[].class, stringValue); boolean optional = resolveAnnotationValue(Boolean.class, optionalValue); if (type.getKind() != TypeKind.DECLARED) { @@ -78,7 +77,7 @@ } if (!classSubstition.getAnnotationType().asElement().equals(((DeclaredType) type).asElement())) { - if (!className.equals(STRING_VALUE_DEFAULT)) { + if (classNames.length != 0) { String msg = "The usage of value and className is exclusive."; env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, stringValue); env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, typeValue); @@ -87,11 +86,15 @@ return (TypeElement) ((DeclaredType) type).asElement(); } - if (!className.equals(STRING_VALUE_DEFAULT)) { - TypeElement typeElement = env.getElementUtils().getTypeElement(className); - if (typeElement == null && !optional) { - env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue); + if (classNames.length != 0) { + TypeElement typeElement = null; + for (String className : classNames) { + typeElement = env.getElementUtils().getTypeElement(className); + if (typeElement == null && !optional) { + env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue); + } } + return typeElement; } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java Sat Jan 31 19:03:33 2015 +0100 @@ -25,7 +25,10 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.replacements.nodes.*; -@ClassSubstitution(className = "org.openjdk.jmh.infra.Blackhole", optional = true) +/** + * Substitutions for both the old and new versions of JMH Blackhole helper classes. + */ +@ClassSubstitution(className = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"}, optional = true) public class BlackholeSubstitutions { @SuppressWarnings("unused") diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.replacements; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.nodes.*; + +@ClassSubstitution(GraalDirectives.class) +public class GraalDirectivesSubstitutions { + + @MethodSubstitution(forced = true) + public static void deoptimize() { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter); + } + + @MethodSubstitution(forced = true) + public static void deoptimizeAndInvalidate() { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter); + } + + @MethodSubstitution(forced = true) + public static boolean inCompiledCode() { + return true; + } + + @MacroSubstitution(forced = true, macro = ControlFlowAnchorNode.class) + public static native void controlFlowAnchor(); + + @MethodSubstitution(forced = true) + public static boolean injectBranchProbability(double probability, boolean condition) { + return BranchProbabilityNode.probability(probability, condition); + } + + @MethodSubstitution(forced = true) + public static void blackhole(boolean value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(byte value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(short value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(char value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(int value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(long value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(float value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(double value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static void blackhole(Object value) { + BlackholeNode.consume(value); + } + + @MethodSubstitution(forced = true) + public static boolean opaque(boolean value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static byte opaque(byte value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static short opaque(short value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static char opaque(char value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static int opaque(int value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static long opaque(long value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static float opaque(float value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static double opaque(double value) { + return OpaqueNode.opaque(value); + } + + @MethodSubstitution(forced = true) + public static T opaque(T value) { + return OpaqueNode.opaque(value); + } +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Sat Jan 31 19:03:33 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.directives.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; @@ -47,6 +48,7 @@ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { BoxingSubstitutions.registerReplacements(replacements); + replacements.registerSubstitutions(GraalDirectives.class, GraalDirectivesSubstitutions.class); if (Intrinsify.getValue()) { replacements.registerSubstitutions(Arrays.class, ArraysSubstitutions.class); replacements.registerSubstitutions(Array.class, ArraySubstitutions.class); @@ -60,13 +62,18 @@ replacements.registerSubstitutions(Short.class, ShortSubstitutions.class); replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class); replacements.registerSubstitutions(Edges.class, EdgesSubstitutions.class); - if (Options.UseBlackholeSubstitution.getValue()) { - replacements.registerSubstitutions(new Type() { - public String getTypeName() { - return "org.openjdk.jmh.infra.Blackhole"; - } - }, BlackholeSubstitutions.class); - } + } + if (Options.UseBlackholeSubstitution.getValue()) { + replacements.registerSubstitutions(new Type() { + public String getTypeName() { + return "org.openjdk.jmh.infra.Blackhole"; + } + }, BlackholeSubstitutions.class); + replacements.registerSubstitutions(new Type() { + public String getTypeName() { + return "org.openjdk.jmh.logic.BlackHole"; + } + }, BlackholeSubstitutions.class); } } } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sat Jan 31 19:03:33 2015 +0100 @@ -162,7 +162,12 @@ private Executable originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) { Class originalClass = classSubstitution.value(); if (originalClass == ClassSubstitution.class) { - originalClass = resolveClass(classSubstitution.className(), classSubstitution.optional()); + for (String className : classSubstitution.className()) { + originalClass = resolveClass(className, classSubstitution.optional()); + if (originalClass != null) { + break; + } + } if (originalClass == null) { // optional class was not found return null; @@ -334,18 +339,26 @@ return null; } - private static String getOriginalInternalName(Class substitutions) { + private static boolean checkSubstitutionInternalName(Class substitutions, String internalName) { ClassSubstitution cs = substitutions.getAnnotation(ClassSubstitution.class); assert cs != null : substitutions + " must be annotated by " + ClassSubstitution.class.getSimpleName(); if (cs.value() == ClassSubstitution.class) { - return toInternalName(cs.className()); + for (String className : cs.className()) { + if (toInternalName(className).equals(internalName)) { + return true; + } + } + assert false : internalName + " not found in " + Arrays.toString(cs.className()); + } else { + String originalInternalName = toInternalName(cs.value().getName()); + assert originalInternalName.equals(internalName) : originalInternalName + " != " + internalName; } - return toInternalName(cs.value().getName()); + return true; } public void registerSubstitutions(Type original, Class substitutionClass) { String internalName = toInternalName(original.getTypeName()); - assert getOriginalInternalName(substitutionClass).equals(internalName) : getOriginalInternalName(substitutionClass) + " != " + (internalName); + assert checkSubstitutionInternalName(substitutionClass, internalName); Class[] classes = internalNameToSubstitutionClasses.get(internalName); if (classes == null) { classes = new Class[]{substitutionClass}; @@ -592,7 +605,8 @@ if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) { graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null))); } else { - createGraphBuilder(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); + createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply( + graph); } afterParsing(graph); @@ -605,8 +619,9 @@ return graph; } - protected Instance createGraphBuilder(MetaAccessProvider metaAccess, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - return new GraphBuilderPhase.Instance(metaAccess, graphBuilderConfig, optimisticOpts); + protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, + OptimisticOptimizations optimisticOpts) { + return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts); } protected void afterParsing(StructuredGraph graph) { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java Sat Jan 31 19:03:33 2015 +0100 @@ -43,47 +43,29 @@ } @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(boolean v) { - } + public static native void consume(boolean v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(byte v) { - } + public static native void consume(byte v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(short v) { - } + public static native void consume(short v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(char v) { - } + public static native void consume(char v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(int v) { - } + public static native void consume(int v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(long v) { - } + public static native void consume(long v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(float v) { - } + public static native void consume(float v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(double v) { - } + public static native void consume(double v); @NodeIntrinsic - @SuppressWarnings("unused") - public static void consume(Object v) { - } + public static native void consume(Object v); } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java Sat Jan 31 19:03:33 2015 +0100 @@ -25,12 +25,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -/** - * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a - * {@link MemoryCheckpoint}. - */ @NodeInfo public class MathPowNode extends MacroStateSplitNode implements Canonicalizable.Binary { diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/OpaqueNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/OpaqueNode.java Sat Jan 31 19:03:33 2015 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.oracle.graal.replacements.nodes; + +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +@NodeInfo +public class OpaqueNode extends FloatingNode implements LIRLowerable { + + @Input ValueNode value; + + public OpaqueNode(ValueNode value) { + super(value.stamp().unrestricted()); + this.value = value; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + gen.setResult(this, gen.operand(value)); + } + + @NodeIntrinsic + public static native boolean opaque(boolean v); + + @NodeIntrinsic + public static native byte opaque(byte v); + + @NodeIntrinsic + public static native short opaque(short v); + + @NodeIntrinsic + public static native char opaque(char v); + + @NodeIntrinsic + public static native int opaque(int v); + + @NodeIntrinsic + public static native long opaque(long v); + + @NodeIntrinsic + public static native float opaque(float v); + + @NodeIntrinsic + public static native double opaque(double v); + + @NodeIntrinsic + public static native T opaque(T v); +} diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Sat Jan 31 19:03:33 2015 +0100 @@ -177,12 +177,12 @@ Suites suites = suitesProvider.createSuites(); removeInliningPhase(suites); StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); PhaseSuite graphBuilderSuite = getGraphBuilderSuite(suitesProvider); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); CompilationResultBuilderFactory factory = getOptimizedCallTargetInstrumentationFactory(backend.getTarget().arch.getName(), javaMethod); - return compileGraph(graph, null, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null, + return compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null, suites, new CompilationResult(), factory); } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Sat Jan 31 19:03:33 2015 +0100 @@ -94,13 +94,13 @@ public StructuredGraph createInlineGraph(String name) { StructuredGraph graph = new StructuredGraph(name, callInlinedMethod); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), config, TruffleCompilerImpl.Optimizations).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), config, TruffleCompilerImpl.Optimizations).apply(graph); return graph; } public StructuredGraph createRootGraph(String name) { StructuredGraph graph = new StructuredGraph(name, callRootMethod); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph); return graph; } @@ -294,7 +294,7 @@ protected StructuredGraph parseGraph(final ResolvedJavaMethod method, final PhaseContext phaseContext) { final StructuredGraph graph = new StructuredGraph(method); - new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph); + new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), config, optimisticOptimizations).apply(graph); return graph; } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Sat Jan 31 19:03:33 2015 +0100 @@ -153,7 +153,7 @@ CodeCacheProvider codeCache = providers.getCodeCache(); CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); CompilationResult compilationResult = new CompilationResult(name); - result = compileGraph(graph, null, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog, + result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog, suites, compilationResult, CompilationResultBuilderFactory.Default); } catch (Throwable e) { throw Debug.handle(e); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Sat Jan 31 19:03:33 2015 +0100 @@ -664,7 +664,7 @@ * Marks a method that it is considered as a boundary for Truffle partial evaluation. */ @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) public @interface TruffleBoundary { } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleTool.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleTool.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleTool.java Sat Jan 31 19:03:33 2015 +0100 @@ -66,16 +66,23 @@ public abstract class TruffleTool { private enum ToolState { + + /** Not yet installed, inert. */ UNINSTALLED, - ENABLED_INSTALLED, - DISABLED_INSTALLED, + + /** Installed, collecting data. */ + ENABLED, + + /** Installed, not collecting data. */ + DISABLED, + + /** Was installed, but now removed, inactive, and no longer usable. */ DISPOSED; } private ToolState toolState = ToolState.UNINSTALLED; protected TruffleTool() { - } /** @@ -85,11 +92,9 @@ * @throws IllegalStateException if the tool has previously been installed. */ public final void install() { - if (toolState != ToolState.UNINSTALLED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has already been installed"); - } + checkUninstalled(); if (internalInstall()) { - toolState = ToolState.ENABLED_INSTALLED; + toolState = ToolState.ENABLED; } } @@ -97,7 +102,7 @@ * @return whether the tool is currently collecting data. */ public final boolean isEnabled() { - return toolState == ToolState.ENABLED_INSTALLED; + return toolState == ToolState.ENABLED; } /** @@ -107,14 +112,9 @@ * @throws IllegalStateException if not yet installed or disposed. */ public final void setEnabled(boolean isEnabled) { - if (toolState == ToolState.UNINSTALLED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed"); - } - if (toolState == ToolState.DISPOSED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed"); - } + checkInstalled(); internalSetEnabled(isEnabled); - toolState = isEnabled ? ToolState.ENABLED_INSTALLED : ToolState.DISABLED_INSTALLED; + toolState = isEnabled ? ToolState.ENABLED : ToolState.DISABLED; } /** @@ -123,12 +123,7 @@ * @throws IllegalStateException if not yet installed or disposed. */ public final void reset() { - if (toolState == ToolState.UNINSTALLED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed"); - } - if (toolState == ToolState.DISPOSED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed"); - } + checkInstalled(); internalReset(); } @@ -139,12 +134,7 @@ * @throws IllegalStateException if not yet installed or disposed. */ public final void dispose() { - if (toolState == ToolState.UNINSTALLED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed"); - } - if (toolState == ToolState.DISPOSED) { - throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed"); - } + checkInstalled(); internalDispose(); toolState = ToolState.DISPOSED; } @@ -156,7 +146,7 @@ /** * No subclass action required. - * + * * @param isEnabled */ protected void internalSetEnabled(boolean isEnabled) { @@ -166,4 +156,29 @@ protected abstract void internalDispose(); + /** + * Ensure that the tool is currently installed. + * + * @throws IllegalStateException + */ + private void checkInstalled() throws IllegalStateException { + if (toolState == ToolState.UNINSTALLED) { + throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed"); + } + if (toolState == ToolState.DISPOSED) { + throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed"); + } + } + + /** + * Ensure that the tool has not yet been installed. + * + * @throws IllegalStateException + */ + private void checkUninstalled() { + if (toolState != ToolState.UNINSTALLED) { + throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has already been installed"); + } + } + } diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Sat Jan 31 19:03:33 2015 +0100 @@ -437,6 +437,9 @@ * that intercepts execution events at the node and routes them to any {@link Instrument}s that * have been attached to the {@link Probe}. Only one {@link Probe} may be installed at each * node; subsequent calls return the one already installed. + *

+ * Note: instrumentation requires a appropriate {@link WrapperNode}, which must be + * provided by {@link #createWrapperNode()}. * * @see Instrument */ @@ -449,7 +452,7 @@ *

    *
  1. implements {@link WrapperNode}
  2. *
  3. has {@code this} as it's child, and
  4. - *
  5. whose type is suitable for (unsafe) replacement of {@code this} in the parent.
  6. + *
  7. whose type is safe for replacement of {@code this} in the parent.
  8. *
* * @return an appropriately typed {@link WrapperNode} if {@link #isInstrumentable()}. diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Sat Jan 31 19:03:33 2015 +0100 @@ -362,15 +362,6 @@ return childrenFields; } - public NodeField findField(long fieldOffset) { - for (NodeField field : getFields()) { - if (field.getOffset() == fieldOffset) { - return field; - } - } - return null; - } - @Override public int hashCode() { return clazz.hashCode(); @@ -665,20 +656,18 @@ NodeClass parentNodeClass = NodeClass.get(parent.getClass()); for (NodeField field : parentNodeClass.getChildFields()) { - final long fieldOffset = field.getOffset(); - if (unsafe.getObject(parent, fieldOffset) == child) { - return parentNodeClass.findField(fieldOffset); + if (field.getObject(parent) == child) { + return field; } } for (NodeField field : parentNodeClass.getChildrenFields()) { - final long fieldOffset = field.getOffset(); - Object arrayObject = unsafe.getObject(parent, fieldOffset); + Object arrayObject = field.getObject(parent); if (arrayObject != null) { Object[] array = (Object[]) arrayObject; for (int i = 0; i < array.length; i++) { if (array[i] == child) { - return parentNodeClass.findField(fieldOffset); + return field; } } } @@ -1091,6 +1080,7 @@ final StringBuilder sb = new StringBuilder(); sb.append("source:"); sb.append(" (" + section.getCharIndex() + "," + (section.getCharEndIndex() - 1) + ")"); + sb.append(" line=" + section.getLineLocation().getLineNumber()); sb.append(" len=" + srcText.length()); sb.append(" text=\"" + srcText + "\""); return sb.toString(); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Sat Jan 31 19:03:33 2015 +0100 @@ -96,8 +96,12 @@ */ private final TruffleEventReceiver eventReceiver = new DefaultEventReceiver() { @Override + public void enter(Node node, VirtualFrame frame) { + internalReceive(node); + } + @TruffleBoundary - public void enter(Node node, VirtualFrame frame) { + private void internalReceive(Node node) { if (isEnabled()) { final Class nodeClass = node.getClass(); AtomicLong nodeCounter = counters.get(nodeClass); diff -r 687479c0cd3e -r db390d92bb16 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java Wed Jan 28 15:07:54 2015 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java Sat Jan 31 19:03:33 2015 +0100 @@ -44,36 +44,22 @@ */ public boolean visit(Node node) { - if (node.isInstrumentable()) { - - if (node instanceof SLStatementNode) { - - // Distinguish between SLExpressionNode and SLStatementNode since some of the - // generated factory methods that require SLExpressionNodes as parameters. - // Since - // SLExpressionNodes are a subclass of SLStatementNode, check if something is an - // SLExpressionNode first. - if (node instanceof SLExpressionNode && node.getParent() != null) { - SLExpressionNode expressionNode = (SLExpressionNode) node; - if (expressionNode.getSourceSection() != null) { - Probe probe = expressionNode.probe(); + if (node instanceof SLStatementNode && node.getParent() != null && node.getSourceSection() != null) { + // All SL nodes are instrumentable, but treat expressions specially - if (node instanceof SLWriteLocalVariableNode) { - probe.tagAs(STATEMENT, null); - probe.tagAs(ASSIGNMENT, null); - } - } - } else if (node instanceof SLStatementNode && node.getParent() != null) { - - SLStatementNode statementNode = (SLStatementNode) node; - if (statementNode.getSourceSection() != null) { - Probe probe = statementNode.probe(); - probe.tagAs(STATEMENT, null); - - if (node instanceof SLWhileNode) { - probe.tagAs(START_LOOP, null); - } - } + if (node instanceof SLExpressionNode) { + SLExpressionNode expressionNode = (SLExpressionNode) node; + Probe probe = expressionNode.probe(); + if (node instanceof SLWriteLocalVariableNode) { + probe.tagAs(STATEMENT, null); + probe.tagAs(ASSIGNMENT, null); + } + } else { + SLStatementNode statementNode = (SLStatementNode) node; + Probe probe = statementNode.probe(); + probe.tagAs(STATEMENT, null); + if (node instanceof SLWhileNode) { + probe.tagAs(START_LOOP, null); } } } diff -r 687479c0cd3e -r db390d92bb16 mx/mx_graal.py --- a/mx/mx_graal.py Wed Jan 28 15:07:54 2015 +0100 +++ b/mx/mx_graal.py Sat Jan 31 19:03:33 2015 +0100 @@ -1360,7 +1360,7 @@ if not containsF: jmhArgs += ['-f1'] - # find all projects with the JMH dependency + # find all projects with a direct JMH dependency jmhProjects = [] for p in mx.projects(): if 'JMH' in p.deps: diff -r 687479c0cd3e -r db390d92bb16 mx/suite.py --- a/mx/suite.py Wed Jan 28 15:07:54 2015 +0100 +++ b/mx/suite.py Sat Jan 31 19:03:33 2015 +0100 @@ -220,6 +220,25 @@ "workingSets" : "API,Graal", }, + "com.oracle.graal.api.directives" : { + "subDir" : "graal", + "sourceDirs" : ["src"], + "checkstyle" : "com.oracle.graal.graph", + "javaCompliance" : "1.8", + "workingSets" : "API,Graal", + }, + + "com.oracle.graal.api.directives.test" : { + "subDir" : "graal", + "sourceDirs" : ["src"], + "checkstyle" : "com.oracle.graal.graph", + "dependencies" : [ + "com.oracle.graal.compiler.test", + ], + "javaCompliance" : "1.8", + "workingSets" : "API,Graal", + }, + "com.oracle.graal.api.runtime" : { "subDir" : "graal", "sourceDirs" : ["src"], @@ -582,6 +601,7 @@ "subDir" : "graal", "sourceDirs" : ["src"], "dependencies" : [ + "com.oracle.graal.api.directives", "com.oracle.graal.compiler", "com.oracle.graal.java", "com.oracle.graal.word", @@ -798,6 +818,7 @@ "com.oracle.graal.phases", ], "checkstyle" : "com.oracle.graal.graph", + "annotationProcessors" : ["com.oracle.graal.service.processor"], "javaCompliance" : "1.8", "workingSets" : "Graal,Java", }, @@ -854,6 +875,7 @@ "subDir" : "graal", "sourceDirs" : ["src"], "dependencies" : [ + "com.oracle.graal.api.directives", "com.oracle.graal.test", "com.oracle.graal.printer", "com.oracle.graal.runtime", diff -r 687479c0cd3e -r db390d92bb16 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Wed Jan 28 15:07:54 2015 +0100 +++ b/src/share/vm/graal/graalRuntime.cpp Sat Jan 31 19:03:33 2015 +0100 @@ -38,7 +38,6 @@ #include "runtime/reflection.hpp" #include "utilities/debug.hpp" -address GraalRuntime::_external_deopt_i2c_entry = NULL; jobject GraalRuntime::_HotSpotGraalRuntime_instance = NULL; bool GraalRuntime::_HotSpotGraalRuntime_initialized = false; bool GraalRuntime::_shutdown_called = false; @@ -60,13 +59,6 @@ graal_compute_offsets(); -#ifdef TARGET_ARCH_x86 -#ifdef _LP64 - // Only supported on x86_64 for now - _external_deopt_i2c_entry = create_external_deopt_i2c(); -#endif -#endif - // Ensure _non_oop_bits is initialized Universe::non_oop_word(); @@ -89,39 +81,6 @@ return buffer_blob; } -address GraalRuntime::create_external_deopt_i2c() { - ResourceMark rm; - BufferBlob* buffer = BufferBlob::create("externalDeopt", 1*K); - CodeBuffer cb(buffer); - short buffer_locs[20]; - cb.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); - MacroAssembler masm(&cb); - - int total_args_passed = 6; - - BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); - VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); - int i = 0; - sig_bt[i++] = T_INT; - sig_bt[i++] = T_LONG; - sig_bt[i++] = T_VOID; // long stakes 2 slots - sig_bt[i++] = T_INT; - sig_bt[i++] = T_OBJECT; - sig_bt[i++] = T_INT; // The number of actual arguments passed to the method. - - int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); - - SharedRuntime::gen_i2c_adapter(&masm, total_args_passed, comp_args_on_stack, sig_bt, regs, total_args_passed - 1); - masm.flush(); - - AdapterBlob* adapter = AdapterBlob::create(&cb); - if (PrintAdapterHandlers) { - tty->print_cr("Decoding external_deopt_i2c"); - Disassembler::decode(adapter->code_begin(), adapter->code_end()); - } - return adapter->code_begin(); -} - BasicType GraalRuntime::kindToBasicType(jchar ch) { switch(ch) { case 'z': return T_BOOLEAN; diff -r 687479c0cd3e -r db390d92bb16 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Wed Jan 28 15:07:54 2015 +0100 +++ b/src/share/vm/graal/graalRuntime.hpp Sat Jan 31 19:03:33 2015 +0100 @@ -33,7 +33,6 @@ static jobject _HotSpotGraalRuntime_instance; static bool _HotSpotGraalRuntime_initialized; - static address _external_deopt_i2c_entry; static const char* _generated_sources_sha1; static bool _shutdown_called; @@ -222,11 +221,6 @@ static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS); static BasicType kindToBasicType(jchar ch); - static address create_external_deopt_i2c(); - static address get_external_deopt_i2c_entry() { - guarantee(_external_deopt_i2c_entry != NULL, "unsupported"); - return _external_deopt_i2c_entry; - } // The following routines are all called from compiled Graal code