# HG changeset patch # User Doug Simon # Date 1363815033 -3600 # Node ID 102b5249e97ee41cb5f914294a350038e12c6442 # Parent 2361bf148c064a1bb3f6f24d1547b2fd6707e023 rename projects: *snippets* -> *replacements* (GRAAL-178) diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2013, 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.amd64; + +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.ConvertNode.Op; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match + * the semantics of the JVM specification. + */ +public class AMD64ConvertSnippets implements Snippets { + + /** + * Converts a float to an int. + *

+ * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the + * conversion. If the float value is a NaN, infinity or if the result of the conversion is + * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and + * extra tests are required on the float value to return the correct int value. + * + * @param input the float being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static int f2i(@Parameter("input") float input, @Parameter("result") int result) { + if (result == Integer.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Float.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0f) { + // input is > 0 -> return max int + return Integer.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a float to a long. + *

+ * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the + * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns + * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct + * long value. + * + * @param input the float being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static long f2l(@Parameter("input") float input, @Parameter("result") long result) { + if (result == Long.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Float.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0f) { + // input is > 0 -> return max int + return Long.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a double to an int. + *

+ * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the + * conversion. If the double value is a NaN, infinity or if the result of the conversion is + * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and + * extra tests are required on the double value to return the correct int value. + * + * @param input the double being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static int d2i(@Parameter("input") double input, @Parameter("result") int result) { + if (result == Integer.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Double.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0d) { + // input is positive -> return maxInt + return Integer.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a double to a long. + *

+ * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the + * conversion. If the double value is a NaN, infinity or if the result of the conversion is + * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra + * tests are required on the double value to return the correct long value. + * + * @param input the double being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static long d2l(@Parameter("input") double input, @Parameter("result") long result) { + if (result == Long.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Double.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0d) { + // input is positive -> return maxInt + return Long.MAX_VALUE; + } + } + return result; + } + + public static class Templates extends AbstractTemplates { + + private final ResolvedJavaMethod f2i; + private final ResolvedJavaMethod f2l; + private final ResolvedJavaMethod d2i; + private final ResolvedJavaMethod d2l; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target, AMD64ConvertSnippets.class); + f2i = snippet("f2i", float.class, int.class); + f2l = snippet("f2l", float.class, long.class); + d2i = snippet("d2i", double.class, int.class); + d2l = snippet("d2l", double.class, long.class); + } + + public void lower(ConvertNode convert, LoweringTool tool) { + if (convert.opcode == Op.F2I) { + lower0(convert, tool, f2i); + } else if (convert.opcode == Op.F2L) { + lower0(convert, tool, f2l); + } else if (convert.opcode == Op.D2I) { + lower0(convert, tool, d2i); + } else if (convert.opcode == Op.D2L) { + lower0(convert, tool, d2l); + } + } + + private void lower0(ConvertNode convert, LoweringTool tool, ResolvedJavaMethod snippet) { + StructuredGraph graph = (StructuredGraph) convert.graph(); + + // Insert a unique placeholder node in place of the Convert node so that the + // Convert node can be used as an input to the snippet. All usage of the + // Convert node are replaced by the placeholder which in turn is replaced by the + // snippet. + + LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp())); + convert.replaceAtUsages(replacee); + Key key = new Key(snippet); + Arguments arguments = arguments("input", convert.value()).add("result", convert); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, arguments); + template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, arguments); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/overview.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/overview.html Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the com.oracle.graal.snippets.test project. + + + diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/CheckCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/CheckCastTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011, 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.meta.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests the implementation of checkcast, allowing profiling information to be manually specified. + */ +public class CheckCastTest extends TypeCheckTest { + + @Override + protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); + if (ccn != null) { + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); + graph.replaceFixedWithFixed(ccn, ccnNew); + } + } + + @LongTest + public void test1() { + test("asNumber", profile(), 111); + test("asNumber", profile(Integer.class), 111); + test("asNumber", profile(Long.class, Short.class), 111); + test("asNumberExt", profile(), 111); + test("asNumberExt", profile(Integer.class), 111); + test("asNumberExt", profile(Long.class, Short.class), 111); + } + + @LongTest + public void test2() { + test("asString", profile(), "111"); + test("asString", profile(String.class), "111"); + test("asString", profile(String.class), "111"); + + final String nullString = null; + test("asString", profile(), nullString); + test("asString", profile(String.class), nullString); + test("asString", profile(String.class), nullString); + + test("asStringExt", profile(), "111"); + test("asStringExt", profile(String.class), "111"); + test("asStringExt", profile(String.class), "111"); + } + + @LongTest + public void test3() { + test("asNumber", profile(), "111"); + } + + @LongTest + public void test4() { + test("asString", profile(String.class), 111); + } + + @LongTest + public void test5() { + test("asNumberExt", profile(), "111"); + } + + @LongTest + public void test6() { + test("asStringExt", profile(String.class), 111); + } + + @LongTest + public void test7() { + Throwable throwable = new Exception(); + test("asThrowable", profile(), throwable); + test("asThrowable", profile(Throwable.class), throwable); + test("asThrowable", profile(Exception.class, Error.class), throwable); + } + + @LongTest + public void test8() { + test("arrayStore", new Object[100], "111"); + } + + @LongTest + public void test8_1() { + test("arrayFill", new Object[100], "111"); + } + + public static Number asNumber(Object o) { + return (Number) o; + } + + public static String asString(Object o) { + return (String) o; + } + + public static Throwable asThrowable(Object o) { + return (Throwable) o; + } + + public static ValueNode asValueNode(Object o) { + return (ValueNode) o; + } + + public static Number asNumberExt(Object o) { + Number n = (Number) o; + return n.intValue() + 10; + } + + public static String asStringExt(Object o) { + String s = (String) o; + return "#" + s; + } + + public static Object[] arrayStore(Object[] arr, Object value) { + arr[15] = value; + return arr; + } + + public static Object[] arrayFill(Object[] arr, Object value) { + for (int i = 0; i < arr.length; i++) { + arr[i] = value; + } + return arr; + } + + static class Depth1 implements Cloneable { + } + + static class Depth2 extends Depth1 { + } + + static class Depth3 extends Depth2 { + } + + static class Depth4 extends Depth3 { + } + + static class Depth5 extends Depth4 { + } + + static class Depth6 extends Depth5 { + } + + static class Depth7 extends Depth6 { + } + + static class Depth8 extends Depth7 { + } + + static class Depth9 extends Depth8 { + } + + static class Depth10 extends Depth9 { + } + + static class Depth11 extends Depth10 { + } + + static class Depth12 extends Depth11 { + } + + static class Depth13 extends Depth12 { + } + + static class Depth14 extends Depth12 { + } + + public static Depth12 asDepth12(Object o) { + return (Depth12) o; + } + + public static Depth12[][] asDepth12Arr(Object o) { + return (Depth12[][]) o; + } + + public static Cloneable asCloneable(Object o) { + return (Cloneable) o; + } + + @LongTest + public void test9() { + Object o = new Depth13(); + test("asDepth12", profile(), o); + test("asDepth12", profile(Depth13.class), o); + test("asDepth12", profile(Depth13.class, Depth14.class), o); + } + + @LongTest + public void test10() { + Object o = new Depth13[3][]; + test("asDepth12Arr", o); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 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.test.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests for {@link InstanceOfDynamicNode}. + */ +public class InstanceOfDynamicTest extends GraalCompilerTest { + + public static int id(int value) { + return value; + } + + @LongTest + public void test100() { + final Object nul = null; + test("isStringDynamic", nul); + test("isStringDynamic", "object"); + test("isStringDynamic", Object.class); + } + + @LongTest + public void test101() { + final Object nul = null; + test("isStringIntDynamic", nul); + test("isStringIntDynamic", "object"); + test("isStringIntDynamic", Object.class); + } + + @LongTest + public void test103() { + test("isInstanceDynamic", String.class, null); + test("isInstanceDynamic", String.class, "object"); + test("isInstanceDynamic", String.class, Object.class); + test("isInstanceDynamic", int.class, null); + test("isInstanceDynamic", int.class, "Object"); + test("isInstanceDynamic", int.class, Object.class); + } + + @LongTest + public void test104() { + test("isInstanceIntDynamic", String.class, null); + test("isInstanceIntDynamic", String.class, "object"); + test("isInstanceIntDynamic", String.class, Object.class); + test("isInstanceIntDynamic", int.class, null); + test("isInstanceIntDynamic", int.class, "Object"); + test("isInstanceIntDynamic", int.class, Object.class); + } + + public static boolean isStringDynamic(Object o) { + return String.class.isInstance(o); + } + + public static int isStringIntDynamic(Object o) { + if (String.class.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } + + public static boolean isInstanceDynamic(Class c, Object o) { + return c.isInstance(o); + } + + public static int isInstanceIntDynamic(Class c, Object o) { + if (c.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2011, 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 java.util.*; + + +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.Mark; +import com.oracle.graal.api.code.CompilationResult.Site; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.CheckCastTest.*; + +/** + * Tests the implementation of instanceof, allowing profiling information to be manually specified. + */ +public class InstanceOfTest extends TypeCheckTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + @Override + protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); + if (ion != null) { + InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile)); + graph.replaceFloating(ion, ionNew); + } + } + + @LongTest + public void test1() { + test("isString", profile(), "object"); + test("isString", profile(String.class), "object"); + + test("isString", profile(), Object.class); + test("isString", profile(String.class), Object.class); + } + + @LongTest + public void test2() { + test("isStringInt", profile(), "object"); + test("isStringInt", profile(String.class), "object"); + + test("isStringInt", profile(), Object.class); + test("isStringInt", profile(String.class), Object.class); + } + + @LongTest + public void test2_1() { + test("isStringIntComplex", profile(), "object"); + test("isStringIntComplex", profile(String.class), "object"); + + test("isStringIntComplex", profile(), Object.class); + test("isStringIntComplex", profile(String.class), Object.class); + } + + @LongTest + public void test3() { + Throwable throwable = new Exception(); + test("isThrowable", profile(), throwable); + test("isThrowable", profile(Throwable.class), throwable); + test("isThrowable", profile(Exception.class, Error.class), throwable); + + test("isThrowable", profile(), Object.class); + test("isThrowable", profile(Throwable.class), Object.class); + test("isThrowable", profile(Exception.class, Error.class), Object.class); + } + + @LongTest + public void test3_1() { + onlyFirstIsException(new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Error(), new Exception()); + test("onlyFirstIsException", profile(), new Exception(), new Exception()); + test("onlyFirstIsException", profile(), new Error(), new Error()); + } + + @LongTest + public void test4() { + Throwable throwable = new Exception(); + test("isThrowableInt", profile(), throwable); + test("isThrowableInt", profile(Throwable.class), throwable); + test("isThrowableInt", profile(Exception.class, Error.class), throwable); + + test("isThrowableInt", profile(), Object.class); + test("isThrowableInt", profile(Throwable.class), Object.class); + test("isThrowableInt", profile(Exception.class, Error.class), Object.class); + } + + @LongTest + public void test5() { + Map map = new HashMap<>(); + test("isMap", profile(), map); + test("isMap", profile(HashMap.class), map); + test("isMap", profile(TreeMap.class, HashMap.class), map); + + test("isMap", profile(), Object.class); + test("isMap", profile(HashMap.class), Object.class); + test("isMap", profile(TreeMap.class, HashMap.class), Object.class); + } + + @LongTest + public void test6() { + Map map = new HashMap<>(); + test("isMapInt", profile(), map); + test("isMapInt", profile(HashMap.class), map); + test("isMapInt", profile(TreeMap.class, HashMap.class), map); + + test("isMapInt", profile(), Object.class); + test("isMapInt", profile(HashMap.class), Object.class); + test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); + } + + @LongTest + public void test7() { + Object o = new Depth13(); + test("isDepth12", profile(), o); + test("isDepth12", profile(Depth13.class), o); + test("isDepth12", profile(Depth13.class, Depth14.class), o); + + o = "not a depth"; + test("isDepth12", profile(), o); + test("isDepth12", profile(Depth13.class), o); + test("isDepth12", profile(Depth13.class, Depth14.class), o); + } + + @LongTest + public void test8() { + Object o = new Depth13(); + test("isDepth12Int", profile(), o); + test("isDepth12Int", profile(Depth13.class), o); + test("isDepth12Int", profile(Depth13.class, Depth14.class), o); + + o = "not a depth"; + test("isDepth12Int", profile(), o); + test("isDepth12Int", profile(Depth13.class), o); + test("isDepth12Int", profile(Depth13.class, Depth14.class), o); + } + + public static boolean isString(Object o) { + return o instanceof String; + } + + public static int isStringInt(Object o) { + if (o instanceof String) { + return id(1); + } + return id(0); + } + + public static int isStringIntComplex(Object o) { + if (o instanceof String || o instanceof Integer) { + return id(o instanceof String ? 1 : 0); + } + return id(0); + } + + public static int id(int value) { + return value; + } + + public static boolean isThrowable(Object o) { + return ((Throwable) o) instanceof Exception; + } + + public static int onlyFirstIsException(Throwable t1, Throwable t2) { + if (t1 instanceof Exception ^ t2 instanceof Exception) { + return t1 instanceof Exception ? 1 : -1; + } + return -1; + } + + public static int isThrowableInt(Object o) { + int result = o instanceof Throwable ? 4 : 5; + if (o instanceof Throwable) { + return id(4); + } + return result; + } + + public static boolean isMap(Object o) { + return o instanceof Map; + } + + public static int isMapInt(Object o) { + if (o instanceof Map) { + return id(1); + } + return id(0); + } + + public static boolean isDepth12(Object o) { + return o instanceof Depth12; + } + + public static int isDepth12Int(Object o) { + if (o instanceof Depth12) { + return id(0); + } + return id(0); + } + + abstract static class MySite { + + final int offset; + + MySite(int offset) { + this.offset = offset; + } + } + + static class MyMark extends MySite { + + MyMark(int offset) { + super(offset); + } + } + + abstract static class MySafepoint extends MySite { + + MySafepoint(int offset) { + super(offset); + } + } + + static class MyCall extends MySafepoint { + + MyCall(int offset) { + super(offset); + } + } + + @LongTest + public void test9() { + MyCall callAt63 = new MyCall(63); + MyMark markAt63 = new MyMark(63); + test("compareMySites", callAt63, callAt63); + test("compareMySites", callAt63, markAt63); + test("compareMySites", markAt63, callAt63); + test("compareMySites", markAt63, markAt63); + } + + public static int compareMySites(MySite s1, MySite s2) { + if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { + return s1 instanceof MyMark ? -1 : 1; + } + return s1.offset - s2.offset; + } + + @LongTest + public void test10() { + Mark[] noMarks = {}; + Call callAt63 = new Call(null, 63, 5, true, null); + Mark markAt63 = new Mark(63, "1", noMarks); + test("compareSites", callAt63, callAt63); + test("compareSites", callAt63, markAt63); + test("compareSites", markAt63, callAt63); + test("compareSites", markAt63, markAt63); + } + + public static int compareSites(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + + /** + * This test exists to show the kind of pattern that is be optimizable by + * {@code removeIntermediateMaterialization()} in {@link IfNode}. + *

+ * The test exists in this source file as the transformation was originally motivated by the + * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. + */ + @LongTest + public void test_removeIntermediateMaterialization() { + List list = Arrays.asList("1", "2", "3", "4"); + test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); + test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); + test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); + } + + public static String removeIntermediateMaterialization(List list, Object e, String a, String b) { + boolean test; + if (list == null || e == null) { + test = false; + } else { + test = false; + for (Object i : list) { + if (i.equals(e)) { + test = true; + break; + } + } + } + if (test) { + return a; + } + return b; + } + + abstract static class A { + } + + static class B extends A { + } + + static class C extends B { + } + + abstract static class D extends C { + } + + public static boolean isArrayOfA(Object o) { + return o instanceof A[]; + } + + public static boolean isArrayOfB(Object o) { + return o instanceof B[]; + } + + public static boolean isArrayOfC(Object o) { + return o instanceof C[]; + } + + public static boolean isArrayOfD(Object o) { + return o instanceof D[]; + } + + @LongTest + public void testArray() { + Object aArray = new A[10]; + test("isArrayOfA", aArray); + + Object bArray = new B[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + + Object cArray = new C[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfA", cArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + test("isArrayOfB", cArray); + test("isArrayOfC", aArray); + test("isArrayOfC", bArray); + test("isArrayOfC", cArray); + + Object dArray = new D[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfA", cArray); + test("isArrayOfA", dArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + test("isArrayOfB", cArray); + test("isArrayOfB", dArray); + test("isArrayOfC", aArray); + test("isArrayOfC", bArray); + test("isArrayOfC", cArray); + test("isArrayOfC", dArray); + test("isArrayOfD", aArray); + test("isArrayOfD", bArray); + test("isArrayOfD", cArray); + test("isArrayOfD", dArray); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InvokeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InvokeTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 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 org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +/** + * Tests the implementation of the snippets for lowering the INVOKE* instructions. + */ +public class InvokeTest extends GraalCompilerTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + public interface I { + + String virtualMethod(String s); + } + + public static class A implements I { + + final String name = "A"; + + public String virtualMethod(String s) { + return name + s; + } + } + + @SuppressWarnings("static-method") + private String privateMethod(String s) { + return s; + } + + @Test + public void test1() { + test("invokestatic", "a string"); + test("invokespecialConstructor", "a string"); + test("invokespecial", this, "a string"); + test("invokevirtual", new A(), "a string"); + test("invokevirtual2", new A(), "a string"); + test("invokeinterface", new A(), "a string"); + Object[] args = {null}; + test("invokestatic", args); + test("invokespecialConstructor", args); + test("invokespecial", null, null); + test("invokevirtual", null, null); + test("invokevirtual2", null, null); + test("invokeinterface", null, null); + } + + public static String invokestatic(String s) { + return staticMethod(s); + } + + public static String staticMethod(String s) { + return s; + } + + public static String invokespecialConstructor(String s) { + return new A().virtualMethod(s); + } + + public static String invokespecial(InvokeTest a, String s) { + return a.privateMethod(s); + } + + public static String invokevirtual(A a, String s) { + return a.virtualMethod(s); + } + + public static String invokevirtual2(A a, String s) { + a.virtualMethod(s); + return a.virtualMethod(s); + } + + public static String invokeinterface(I i, String s) { + return i.virtualMethod(s); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2012, 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 static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests if {@link MethodSubstitution}s are inlined correctly. Most test cases only assert that + * there are no remaining invocations in the graph. This is sufficient if the method that is being + * substituted is a native method. For Java methods, additional checks are necessary. + */ +public class MethodSubstitutionTest extends GraalCompilerTest { + + @Test + public void testObjectSubstitutions() { + test("getClass_"); + test("objectHashCode"); + } + + @SuppressWarnings("all") + public static boolean getClass_(Object obj, Class clazz) { + return obj.getClass() == clazz; + } + + @SuppressWarnings("all") + public static int objectHashCode(TestClassA obj) { + return obj.hashCode(); + } + + @Test + public void testClassSubstitutions() { + test("getModifiers"); + test("isInstance"); + test("isInterface"); + test("isArray"); + test("isPrimitive"); + test("getSuperClass"); + test("getComponentType"); + } + + @SuppressWarnings("all") + public static int getModifiers(Class clazz) { + return clazz.getModifiers(); + } + + @SuppressWarnings("all") + public static boolean isInstance(Class clazz) { + return clazz.isInstance(Number.class); + } + + @SuppressWarnings("all") + public static boolean isInterface(Class clazz) { + return clazz.isInterface(); + } + + @SuppressWarnings("all") + public static boolean isArray(Class clazz) { + return clazz.isArray(); + } + + @SuppressWarnings("all") + public static boolean isPrimitive(Class clazz) { + return clazz.isPrimitive(); + } + + @SuppressWarnings("all") + public static Class getSuperClass(Class clazz) { + return clazz.getSuperclass(); + } + + @SuppressWarnings("all") + public static Class getComponentType(Class clazz) { + return clazz.getComponentType(); + } + + @Test + public void testThreadSubstitutions() { + test("currentThread"); + test("threadIsInterrupted"); + test("threadInterrupted"); + } + + @SuppressWarnings("all") + public static Thread currentThread() { + return Thread.currentThread(); + } + + @SuppressWarnings("all") + public static boolean threadIsInterrupted(Thread thread) { + return thread.isInterrupted(); + } + + @SuppressWarnings("all") + public static boolean threadInterrupted() { + return Thread.interrupted(); + } + + @Test + public void testSystemSubstitutions() { + test("systemTime"); + test("systemIdentityHashCode"); + } + + @SuppressWarnings("all") + public static long systemTime() { + return System.currentTimeMillis() + System.nanoTime(); + } + + @SuppressWarnings("all") + public static int systemIdentityHashCode(Object obj) { + return System.identityHashCode(obj); + } + + @Test + public void testUnsafeSubstitutions() { + test("unsafeCompareAndSwapInt"); + test("unsafeCompareAndSwapLong"); + test("unsafeCompareAndSwapObject"); + + test("unsafeGetBoolean"); + test("unsafeGetByte"); + test("unsafeGetShort"); + test("unsafeGetChar"); + test("unsafeGetInt"); + test("unsafeGetFloat"); + test("unsafeGetDouble"); + test("unsafeGetObject"); + + test("unsafePutBoolean"); + test("unsafePutByte"); + test("unsafePutShort"); + test("unsafePutChar"); + test("unsafePutInt"); + test("unsafePutFloat"); + test("unsafePutDouble"); + test("unsafePutObject"); + + test("unsafeDirectMemoryRead"); + test("unsafeDirectMemoryWrite"); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapInt(obj, offset, 0, 1); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapLong(obj, offset, 0, 1); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapObject(obj, offset, null, new Object()); + } + + @SuppressWarnings("all") + public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) { + return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) { + return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) { + return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) { + return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) { + return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) { + return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) { + return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) { + return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) { + return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) { + unsafe.putBoolean(obj, offset, value); + unsafe.putBooleanVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) { + unsafe.putByte(obj, offset, value); + unsafe.putByteVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) { + unsafe.putShort(obj, offset, value); + unsafe.putShortVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) { + unsafe.putChar(obj, offset, value); + unsafe.putCharVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) { + unsafe.putInt(obj, offset, value); + unsafe.putIntVolatile(obj, offset, value); + unsafe.putOrderedInt(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) { + unsafe.putLong(obj, offset, value); + unsafe.putLongVolatile(obj, offset, value); + unsafe.putOrderedLong(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) { + unsafe.putFloat(obj, offset, value); + unsafe.putFloatVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) { + unsafe.putDouble(obj, offset, value); + unsafe.putDoubleVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) { + unsafe.putObject(obj, offset, value); + unsafe.putObjectVolatile(obj, offset, value); + unsafe.putOrderedObject(obj, offset, value); + } + + @SuppressWarnings("all") + public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) { + // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist + return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address); + } + + @SuppressWarnings("all") + public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) { + // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist + unsafe.putByte(address, value); + unsafe.putShort(address, value); + unsafe.putChar(address, (char) value); + unsafe.putInt(address, value); + unsafe.putLong(address, value); + unsafe.putFloat(address, value); + unsafe.putDouble(address, value); + } + + @Test + public void testMathSubstitutions() { + assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), MathIntrinsicNode.class); // Java + test("math"); + } + + @SuppressWarnings("all") + public static double mathAbs(double value) { + return Math.abs(value); + } + + @SuppressWarnings("all") + public static double math(double value) { + return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); + // Math.exp(value) + + // Math.pow(value, 13); + } + + @Test + public void testIntegerSubstitutions() { + assertInGraph(test("integerReverseBytes"), ReverseBytesNode.class); // Java + assertInGraph(test("integerNumberOfLeadingZeros"), BitScanReverseNode.class); // Java + assertInGraph(test("integerNumberOfTrailingZeros"), BitScanForwardNode.class); // Java + assertInGraph(test("integerBitCount"), BitCountNode.class); // Java + } + + @SuppressWarnings("all") + public static int integerReverseBytes(int value) { + return Integer.reverseBytes(value); + } + + @SuppressWarnings("all") + public static int integerNumberOfLeadingZeros(int value) { + return Integer.numberOfLeadingZeros(value); + } + + @SuppressWarnings("all") + public static int integerNumberOfTrailingZeros(int value) { + return Integer.numberOfTrailingZeros(value); + } + + @SuppressWarnings("all") + public static int integerBitCount(int value) { + return Integer.bitCount(value); + } + + @Test + public void testLongSubstitutions() { + assertInGraph(test("longReverseBytes"), ReverseBytesNode.class); // Java + assertInGraph(test("longNumberOfLeadingZeros"), BitScanReverseNode.class); // Java + assertInGraph(test("longNumberOfTrailingZeros"), BitScanForwardNode.class); // Java + assertInGraph(test("longBitCount"), BitCountNode.class); // Java + } + + @SuppressWarnings("all") + public static long longReverseBytes(long value) { + return Long.reverseBytes(value); + } + + @SuppressWarnings("all") + public static long longNumberOfLeadingZeros(long value) { + return Long.numberOfLeadingZeros(value); + } + + @SuppressWarnings("all") + public static long longNumberOfTrailingZeros(long value) { + return Long.numberOfTrailingZeros(value); + } + + @SuppressWarnings("all") + public static int longBitCount(long value) { + return Long.bitCount(value); + } + + @Test + public void testFloatSubstitutions() { + assertInGraph(test("floatToIntBits"), ConvertNode.class); // Java + test("intBitsToFloat"); + } + + @SuppressWarnings("all") + public static int floatToIntBits(float value) { + return Float.floatToIntBits(value); + } + + @SuppressWarnings("all") + public static float intBitsToFloat(int value) { + return Float.intBitsToFloat(value); + } + + @Test + public void testDoubleSubstitutions() { + assertInGraph(test("doubleToLongBits"), ConvertNode.class); // Java + test("longBitsToDouble"); + } + + @SuppressWarnings("all") + public static long doubleToLongBits(double value) { + return Double.doubleToLongBits(value); + } + + @SuppressWarnings("all") + public static double longBitsToDouble(long value) { + return Double.longBitsToDouble(value); + } + + private StructuredGraph test(final String snippet) { + return Debug.scope("MethodSubstitutionTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable() { + + @Override + public StructuredGraph call() { + StructuredGraph graph = parse(snippet); + PhasePlan phasePlan = getDefaultPhasePlan(); + Assumptions assumptions = new Assumptions(true); + new ComputeProbabilityPhase().apply(graph); + Debug.dump(graph, "Graph"); + new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + Debug.dump(graph, "Graph"); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + + assertNotInGraph(graph, Invoke.class); + return graph; + } + }); + } + + private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + private static StructuredGraph assertInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + return graph; + } + } + fail("Graph does not contain a node of class " + clazz.getName()); + return graph; + } + + private static class TestClassA { + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MonitorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MonitorTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2012, 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 org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class MonitorTest extends GraalCompilerTest { + + @Test + public void test0() { + test("lockObjectSimple", new Object(), new Object()); + test("lockObjectSimple", new Object(), null); + } + + @Test + public void test0_1() { + test("lockThisSimple", "test1", new Object()); + test("lockThisSimple", "test1", null); + } + + @Test + public void test0_2() { + test("lockObjectSimple", null, "test1"); + } + + @Test + public void test1_1() { + test("lockObject", new Object(), "test1", new String[1]); + } + + @Test + public void test1_2() { + test("lockObject", null, "test1_1", new String[1]); + } + + @Test + public void test2() { + test("lockThis", "test2", new String[1]); + } + + /** + * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}. + */ + @Test + public void test3() { + test("lockLocalObject", "test3", new String[1]); + } + + /** + * Tests recursive locking of objects which should be biasable. + */ + @Test + public void test4() { + Chars src = new Chars("1234567890".toCharArray()); + Chars dst = new Chars(src.data.length); + test("copyObj", src, dst, 100); + } + + /** + * Tests recursive locking of objects which do not appear to be biasable. + */ + @Test + public void test5() { + char[] src = "1234567890".toCharArray(); + char[] dst = new char[src.length]; + test("copyArr", src, dst, 100); + } + + /** + * Extends {@link #test4()} with contention. + */ + @Test + public void test6() { + Chars src = new Chars("1234567890".toCharArray()); + Chars dst = new Chars(src.data.length); + int n = Runtime.getRuntime().availableProcessors(); + testN(n, "copyObj", src, dst, 100); + } + + /** + * Extends {@link #test5()} with contention. + */ + @Test + public void test7() { + char[] src = "1234567890".toCharArray(); + char[] dst = new char[src.length]; + int n = Runtime.getRuntime().availableProcessors(); + testN(n, "copyArr", src, dst, 100); + } + + private static String setAndGet(String[] box, String value) { + synchronized (box) { + box[0] = null; + } + + // Do a GC while a object is locked (by the caller) + System.gc(); + + synchronized (box) { + box[0] = value; + } + return box[0]; + } + + public static Object lockObjectSimple(Object o, Object value) { + synchronized (o) { + value.hashCode(); + return value; + } + } + + public String lockThisSimple(String value, Object o) { + synchronized (this) { + synchronized (value) { + o.hashCode(); + return value; + } + } + } + + public static String lockObject(Object o, String value, String[] box) { + synchronized (o) { + return setAndGet(box, value); + } + } + + public String lockThis(String value, String[] box) { + synchronized (this) { + return setAndGet(box, value); + } + } + + public static String lockLocalObject(String value, String[] box) { + Object o = new Object(); + synchronized (o) { + return setAndGet(box, value); + } + } + + static class Chars { + + final char[] data; + + public Chars(int size) { + this.data = new char[size]; + } + + public Chars(char[] data) { + this.data = data; + } + } + + public static String copyObj(Chars src, Chars dst, int n) { + System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.data.length); + int total = 0; + for (int j = 0; j < n; j++) { + for (int i = 0; i < src.data.length; i++) { + synchronized (src) { + synchronized (dst) { + synchronized (src) { + synchronized (dst) { + dst.data[i] = src.data[i]; + total++; + } + } + } + } + } + } + System.out.println(Thread.currentThread().getName() + " total " + total); + return new String(dst.data); + } + + public static String copyArr(char[] src, char[] dst, int n) { + System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.length); + int total = 0; + for (int j = 0; j < n; j++) { + for (int i = 0; i < src.length; i++) { + synchronized (src) { + synchronized (dst) { + synchronized (src) { + synchronized (dst) { + dst[i] = src[i]; + total++; + } + } + } + } + } + } + System.out.println(Thread.currentThread().getName() + " total " + total); + return new String(dst); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewArrayTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011, 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 org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of {@code [A]NEWARRAY}. + */ +public class NewArrayTest extends GraalCompilerTest { + + @Override + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); + if (expected instanceof int[]) { + Assert.assertArrayEquals((int[]) expected, (int[]) actual); + } else if (expected instanceof byte[]) { + Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); + } else if (expected instanceof char[]) { + Assert.assertArrayEquals((char[]) expected, (char[]) actual); + } else if (expected instanceof short[]) { + Assert.assertArrayEquals((short[]) expected, (short[]) actual); + } else if (expected instanceof float[]) { + Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); + } else if (expected instanceof long[]) { + Assert.assertArrayEquals((long[]) expected, (long[]) actual); + } else if (expected instanceof double[]) { + Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); + } else if (expected instanceof Object[]) { + Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); + } else { + Assert.fail("non-array value encountered: " + expected); + } + } + + @LongTest + public void test1() { + for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { + test("new" + type + "Array7"); + test("new" + type + "ArrayMinus7"); + test("new" + type + "Array", 7); + test("new" + type + "Array", -7); + test("new" + type + "Array", Integer.MAX_VALUE); + test("new" + type + "Array", Integer.MIN_VALUE); + } + } + + public static Object newCharArray7() { + return new char[7]; + } + + public static Object newCharArrayMinus7() { + return new char[-7]; + } + + public static Object newCharArray(int length) { + return new char[length]; + } + + public static Object newShortArray7() { + return new short[7]; + } + + public static Object newShortArrayMinus7() { + return new short[-7]; + } + + public static Object newShortArray(int length) { + return new short[length]; + } + + public static Object newFloatArray7() { + return new float[7]; + } + + public static Object newFloatArrayMinus7() { + return new float[-7]; + } + + public static Object newFloatArray(int length) { + return new float[length]; + } + + public static Object newLongArray7() { + return new long[7]; + } + + public static Object newLongArrayMinus7() { + return new long[-7]; + } + + public static Object newLongArray(int length) { + return new long[length]; + } + + public static Object newDoubleArray7() { + return new double[7]; + } + + public static Object newDoubleArrayMinus7() { + return new double[-7]; + } + + public static Object newDoubleArray(int length) { + return new double[length]; + } + + public static Object newIntArray7() { + return new int[7]; + } + + public static Object newIntArrayMinus7() { + return new int[-7]; + } + + public static Object newIntArray(int length) { + return new int[length]; + } + + public static Object newByteArray7() { + return new byte[7]; + } + + public static Object newByteArrayMinus7() { + return new byte[-7]; + } + + public static Object newByteArray(int length) { + return new byte[length]; + } + + public static Object newStringArray7() { + return new String[7]; + } + + public static Object newStringArrayMinus7() { + return new String[-7]; + } + + public static Object newStringArray(int length) { + return new String[length]; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewInstanceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewInstanceTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2011, 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 java.util.*; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of {@code NEW}. + */ +public class NewInstanceTest extends GraalCompilerTest { + + @Override + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); + + if (expected instanceof Object[]) { + Assert.assertTrue(actual instanceof Object[]); + Object[] eArr = (Object[]) expected; + Object[] aArr = (Object[]) actual; + Assert.assertTrue(eArr.length == aArr.length); + for (int i = 0; i < eArr.length; i++) { + assertEquals(eArr[i], aArr[i]); + } + } else if (expected.getClass() != Object.class) { + try { + expected.getClass().getDeclaredMethod("equals", Object.class); + super.assertEquals(expected, actual); + } catch (Exception e) { + } + } + } + + @LongTest + public void test1() { + test("newObject"); + } + + @LongTest + public void test2() { + test("newObjectTwice"); + } + + public static Object newObject() { + return new Object(); + } + + @LongTest + public void test3() { + test("newObjectLoop", 100); + } + + @LongTest + public void test4() { + test("newBigObject"); + } + + @LongTest + public void test5() { + test("newSomeObject"); + } + + @LongTest + public void test6() { + test("newEmptyString"); + } + + @LongTest + public void test7() { + test("newString", "value"); + } + + @LongTest + public void test8() { + test("newHashMap", 31); + } + + @LongTest + public void test9() { + test("newRegression", true); + } + + public static Object[] newObjectTwice() { + Object[] res = {new Object(), new Object()}; + return res; + } + + public static Object[] newObjectLoop(int n) { + Object[] res = new Object[n]; + for (int i = 0; i < n; i++) { + res[i] = new Object(); + } + return res; + } + + public static BigObject newBigObject() { + return new BigObject(); + } + + public static SomeObject newSomeObject() { + return new SomeObject(); + } + + public static String newEmptyString() { + return new String(); + } + + public static String newString(String value) { + return new String(value); + } + + public static HashMap newHashMap(int initialCapacity) { + return new HashMap(initialCapacity); + } + + static class SomeObject { + + String name = "o1"; + HashMap map = new HashMap<>(); + + public SomeObject() { + map.put(name, this.getClass()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SomeObject) { + SomeObject so = (SomeObject) obj; + return so.name.equals(name) && so.map.equals(map); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + } + + static class BigObject { + + Object f01; + Object f02; + Object f03; + Object f04; + Object f05; + Object f06; + Object f07; + Object f08; + Object f09; + Object f10; + Object f12; + Object f13; + Object f14; + Object f15; + Object f16; + Object f17; + Object f18; + Object f19; + Object f20; + Object f21; + Object f22; + Object f23; + Object f24; + Object f25; + Object f26; + Object f27; + Object f28; + Object f29; + Object f30; + Object f31; + Object f32; + Object f33; + Object f34; + Object f35; + Object f36; + Object f37; + Object f38; + Object f39; + Object f40; + Object f41; + Object f42; + Object f43; + Object f44; + Object f45; + } + + /** + * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top' + * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the + * allocated B object in the true branch overwrote the allocated array. The cause is that + * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also + * floating. The fix was to make RegisterNode a fixed node (which it should have been in the + * first place). + */ + public static Object newRegression(boolean condition) { + Object result; + if (condition) { + Object[] arr = {0, 1, 2, 3, 4, 5}; + result = new B(); + for (int i = 0; i < arr.length; ++i) { + // If the bug exists, the values of arr will now be deadbeef values + // and the virtual dispatch will cause a segfault. This can result in + // either a VM crash or a spurious NullPointerException. + if (arr[i].equals(Integer.valueOf(i))) { + return false; + } + } + } else { + result = new B(); + } + return result; + } + + static class B { + + long f1 = 0xdeadbeefdeadbe01L; + long f2 = 0xdeadbeefdeadbe02L; + long f3 = 0xdeadbeefdeadbe03L; + long f4 = 0xdeadbeefdeadbe04L; + long f5 = 0xdeadbeefdeadbe05L; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012, 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 java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests the lowering of the MULTIANEWARRAY instruction. + */ +public class NewMultiArrayTest extends GraalCompilerTest { + + private static int rank(ResolvedJavaType type) { + String name = type.getName(); + int dims = 0; + while (dims < name.length() && name.charAt(dims) == '[') { + dims++; + } + return dims; + } + + @Override + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; + if (bottomType != null) { + List snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot(); + assert snapshot != null; + assert snapshot.size() == 1; + + NewMultiArrayNode node = snapshot.get(0); + assert rank(arrayType) == dimensions.length; + int rank = dimensions.length; + ValueNode[] dimensionNodes = new ValueNode[rank]; + for (int i = 0; i < rank; i++) { + dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph)); + } + + NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes)); + graph.replaceFixedWithFixed(node, repl); + forceCompile = true; + } + return super.getCode(method, graph, forceCompile); + } + + @Override + protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + if (bottomType != null) { + try { + return Array.newInstance(bottomClass, dimensions); + } catch (Exception e) { + throw new InvocationTargetException(e); + } + } + return super.referenceInvoke(method, receiver, args); + } + + ResolvedJavaType arrayType; + ResolvedJavaType bottomType; + Class bottomClass; + int[] dimensions; + + @LongTest + public void test1() { + for (Class clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { + bottomClass = clazz; + bottomType = runtime.lookupJavaType(clazz); + arrayType = bottomType; + for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) { + while (rank(arrayType) != rank) { + arrayType = arrayType.getArrayClass(); + } + + dimensions = new int[rank]; + for (int i = 0; i < rank; i++) { + dimensions[i] = 1; + } + + test("newMultiArray"); + } + } + bottomType = null; + arrayType = null; + } + + public static Object newMultiArray() { + // This is merely a template - the NewMultiArrayNode is replaced in getCode() above. + // This also means we need a separate test for correct handling of negative dimensions + // as deoptimization won't do what we want for a graph modified to be different from the + // source bytecode. + return new Object[10][9][8]; + } + + @LongTest + public void test2() { + test("newMultiArrayException"); + } + + public static Object newMultiArrayException() { + return new Object[10][9][-8]; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/PointerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/PointerTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2013, 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 java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Pointer} read and write operations. + */ +public class PointerTest extends GraalCompilerTest implements Snippets { + + private static final Object ID = new Object(); + private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; + private final TargetDescription target; + private final ReplacementsInstaller installer; + + public PointerTest() { + target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); + } + + @Test + public void test_read1() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_read2() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_read3() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION); + } + } + + @Test + public void test_write1() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_write2() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_write3() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); + } + } + + private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + ReadNode read = (ReadNode) graph.start().next(); + Assert.assertEquals(kind.getStackKind(), read.kind()); + + UnsafeCastNode cast = (UnsafeCastNode) read.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) read.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + ReturnNode ret = (ReturnNode) read.next(); + Assert.assertEquals(read, ret.result()); + } + + private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + WriteNode write = (WriteNode) graph.start().next(); + Assert.assertEquals(graph.getLocal(2), write.value()); + Assert.assertEquals(Kind.Void, write.kind()); + Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); + + UnsafeCastNode cast = (UnsafeCastNode) write.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) write.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); + Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); + + ReturnNode ret = (ReturnNode) stateSplit.next(); + Assert.assertEquals(null, ret.result()); + } + + @Snippet + public static byte readByte1(Object o, int offset) { + return Word.fromObject(o).readByte(offset, ID); + } + + @Snippet + public static byte readByte2(Object o, int offset) { + return Word.fromObject(o).readByte(Word.signed(offset), ID); + } + + @Snippet + public static byte readByte3(Object o, int offset) { + return Word.fromObject(o).readByte(offset); + } + + @Snippet + public static void writeByte1(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value, ID); + } + + @Snippet + public static void writeByte2(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeByte3(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value); + } + + @Snippet + public static char readChar1(Object o, int offset) { + return Word.fromObject(o).readChar(offset, ID); + } + + @Snippet + public static char readChar2(Object o, int offset) { + return Word.fromObject(o).readChar(Word.signed(offset), ID); + } + + @Snippet + public static char readChar3(Object o, int offset) { + return Word.fromObject(o).readChar(offset); + } + + @Snippet + public static void writeChar1(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value, ID); + } + + @Snippet + public static void writeChar2(Object o, int offset, char value) { + Word.fromObject(o).writeChar(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeChar3(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value); + } + + @Snippet + public static short readShort1(Object o, int offset) { + return Word.fromObject(o).readShort(offset, ID); + } + + @Snippet + public static short readShort2(Object o, int offset) { + return Word.fromObject(o).readShort(Word.signed(offset), ID); + } + + @Snippet + public static short readShort3(Object o, int offset) { + return Word.fromObject(o).readShort(offset); + } + + @Snippet + public static void writeShort1(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value, ID); + } + + @Snippet + public static void writeShort2(Object o, int offset, short value) { + Word.fromObject(o).writeShort(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeShort3(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value); + } + + @Snippet + public static int readInt1(Object o, int offset) { + return Word.fromObject(o).readInt(offset, ID); + } + + @Snippet + public static int readInt2(Object o, int offset) { + return Word.fromObject(o).readInt(Word.signed(offset), ID); + } + + @Snippet + public static int readInt3(Object o, int offset) { + return Word.fromObject(o).readInt(offset); + } + + @Snippet + public static void writeInt1(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value, ID); + } + + @Snippet + public static void writeInt2(Object o, int offset, int value) { + Word.fromObject(o).writeInt(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeInt3(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value); + } + + @Snippet + public static long readLong1(Object o, int offset) { + return Word.fromObject(o).readLong(offset, ID); + } + + @Snippet + public static long readLong2(Object o, int offset) { + return Word.fromObject(o).readLong(Word.signed(offset), ID); + } + + @Snippet + public static long readLong3(Object o, int offset) { + return Word.fromObject(o).readLong(offset); + } + + @Snippet + public static void writeLong1(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value, ID); + } + + @Snippet + public static void writeLong2(Object o, int offset, long value) { + Word.fromObject(o).writeLong(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeLong3(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value); + } + + @Snippet + public static float readFloat1(Object o, int offset) { + return Word.fromObject(o).readFloat(offset, ID); + } + + @Snippet + public static float readFloat2(Object o, int offset) { + return Word.fromObject(o).readFloat(Word.signed(offset), ID); + } + + @Snippet + public static float readFloat3(Object o, int offset) { + return Word.fromObject(o).readFloat(offset); + } + + @Snippet + public static void writeFloat1(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value, ID); + } + + @Snippet + public static void writeFloat2(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeFloat3(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value); + } + + @Snippet + public static double readDouble1(Object o, int offset) { + return Word.fromObject(o).readDouble(offset, ID); + } + + @Snippet + public static double readDouble2(Object o, int offset) { + return Word.fromObject(o).readDouble(Word.signed(offset), ID); + } + + @Snippet + public static double readDouble3(Object o, int offset) { + return Word.fromObject(o).readDouble(offset); + } + + @Snippet + public static void writeDouble1(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value, ID); + } + + @Snippet + public static void writeDouble2(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeDouble3(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value); + } + + @Snippet + public static Object readObject1(Object o, int offset) { + return Word.fromObject(o).readObject(offset, ID); + } + + @Snippet + public static Object readObject2(Object o, int offset) { + return Word.fromObject(o).readObject(Word.signed(offset), ID); + } + + @Snippet + public static Object readObject3(Object o, int offset) { + return Word.fromObject(o).readObject(offset); + } + + @Snippet + public static void writeObject1(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value, ID); + } + + @Snippet + public static void writeObject2(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeObject3(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value); + } + +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/TypeCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/TypeCheckTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, 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.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; + +/** + * Base class for checkcast and instanceof test classes. + */ +public abstract class TypeCheckTest extends GraalCompilerTest { + + protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); + + protected JavaTypeProfile currentProfile; + + @Override + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; + if (currentProfile != null) { + replaceProfile(graph, currentProfile); + forceCompile = true; + } + return super.getCode(method, graph, forceCompile); + } + + protected JavaTypeProfile profile(Class... types) { + if (types.length == 0) { + return null; + } + ProfiledType[] ptypes = new ProfiledType[types.length]; + for (int i = 0; i < types.length; i++) { + ptypes[i] = new ProfiledType(runtime.lookupJavaType(types[i]), 1.0D / types.length); + } + return new JavaTypeProfile(0.0D, ptypes); + } + + protected void test(String name, JavaTypeProfile profile, Object... args) { + assert currentProfile == null; + currentProfile = profile; + try { + super.test(name, args); + } finally { + currentProfile = null; + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/WordTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/WordTest.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2011, 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 java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Word} type. + */ +public class WordTest extends GraalCompilerTest implements Snippets { + + private final ReplacementsInstaller installer; + + public WordTest() { + TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); + } + + @LongTest + public void construction() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, + Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; + for (long word : words) { + test("unsigned_long", word); + test("unsigned_int", (int) word); + test("signed_long", word); + test("signed_int", (int) word); + } + } + + @LongTest + public void test_arithmetic() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, + Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; + for (long word : words) { + test("unsigned_not", word); + test("signed_not", word); + for (long addend : words) { + test("unsigned_plus_int", word, (int) addend); + test("unsigned_minus_int", word, (int) addend); + test("unsigned_plus_int", word, -((int) addend)); + test("unsigned_minus_int", word, -((int) addend)); + test("unsigned_plus_long", word, addend); + test("unsigned_minus_long", word, addend); + test("unsigned_plus_long", word, -addend); + test("unsigned_minus_long", word, -addend); + test("signed_plus_int", word, (int) addend); + test("signed_minus_int", word, (int) addend); + test("signed_plus_int", word, -((int) addend)); + test("signed_minus_int", word, -((int) addend)); + test("signed_plus_long", word, addend); + test("signed_minus_long", word, addend); + test("signed_plus_long", word, -addend); + test("signed_minus_long", word, -addend); + + test("and_int", word, (int) addend); + test("or_int", word, (int) addend); + test("and_int", word, -((int) addend)); + test("or_int", word, -((int) addend)); + test("and_long", word, addend); + test("or_long", word, addend); + test("and_long", word, -addend); + test("or_long", word, -addend); + } + } + } + + @LongTest + public void test_compare() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; + for (long word1 : words) { + for (long word2 : words) { + for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) { + test(method, word1, word2); + test(method, word2, word1); + } + } + } + } + + @Snippet + public static long unsigned_long(long word) { + return Word.unsigned(word).rawValue(); + } + + @Snippet + public static long unsigned_int(int word) { + return Word.unsigned(word).rawValue(); + } + + @Snippet + public static long signed_long(long word) { + return Word.signed(word).rawValue(); + } + + @Snippet + public static long signed_int(int word) { + return Word.signed(word).rawValue(); + } + + @Snippet + public static long unsigned_plus_int(long word, int addend) { + return Word.unsigned(word).add(addend).rawValue(); + } + + @Snippet + public static long unsigned_minus_int(long word, int addend) { + return Word.unsigned(word).subtract(addend).rawValue(); + } + + @Snippet + public static long unsigned_plus_long(long word, long addend) { + return Word.unsigned(word).add(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long unsigned_minus_long(long word, long addend) { + return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long signed_plus_int(long word, int addend) { + return Word.signed(word).add(addend).rawValue(); + } + + @Snippet + public static long signed_minus_int(long word, int addend) { + return Word.signed(word).subtract(addend).rawValue(); + } + + @Snippet + public static long signed_plus_long(long word, long addend) { + return Word.signed(word).add(Word.signed(addend)).rawValue(); + } + + @Snippet + public static long signed_minus_long(long word, long addend) { + return Word.signed(word).subtract(Word.signed(addend)).rawValue(); + } + + @Snippet + public static long signed_not(long word) { + return Word.signed(word).not().rawValue(); + } + + @Snippet + public static long unsigned_not(long word) { + return Word.unsigned(word).not().rawValue(); + } + + @Snippet + public static boolean aboveOrEqual(long word1, long word2) { + return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2)); + } + + @Snippet + public static boolean above(long word1, long word2) { + return Word.unsigned(word1).aboveThan(Word.unsigned(word2)); + } + + @Snippet + public static boolean belowOrEqual(long word1, long word2) { + return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2)); + } + + @Snippet + public static boolean below(long word1, long word2) { + return Word.unsigned(word1).belowThan(Word.unsigned(word2)); + } + + @Snippet + public static long and_int(long word, int addend) { + return Word.unsigned(word).and(addend).rawValue(); + } + + @Snippet + public static long or_int(long word, int addend) { + return Word.unsigned(word).or(addend).rawValue(); + } + + @Snippet + public static long and_long(long word, long addend) { + return Word.unsigned(word).and(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long or_long(long word, long addend) { + return Word.unsigned(word).or(Word.unsigned(addend)).rawValue(); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/overview.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/overview.html Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the com.oracle.graal.snippets project. + + + diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ClassSubstitution.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ClassSubstitution.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2011, 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 java.lang.annotation.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Denotes a class that substitutes methods of another specified class. The substitute methods are + * exactly those annotated by {@link MethodSubstitution}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ClassSubstitution { + + /** + * Specifies the original class. + *

+ * If the default value is specified for this element, then a non-default value must be given + * for the {@link #className()} element. + */ + Class value() default ClassSubstitution.class; + + /** + * Specifies the original class. + *

+ * This method is provided for cases where the original class is not accessible (according to + * Java language access control rules). + *

+ * 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 ""; + + /** + * Determines if the substitutions are for classes that may not be part of the runtime. + * Substitutions for such classes are omitted if the original classes cannot be found. + */ + boolean optional() default false; + + /** + * Denotes a substitute method. A substitute method can call the original/substituted method by + * making a recursive call to itself. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface MethodSubstitution { + + /** + * Gets the name of the original method. + *

+ * If the default value is specified for this element, then the name of the original method + * is same as the substitute method. + */ + String value() default ""; + + /** + * Determines if the original method is static. + */ + boolean isStatic() default true; + + /** + * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the original + * method. + *

+ * If the default value is specified for this element, then the signature of the original + * method is the same as the substitute method. + */ + String signature() default ""; + } + + /** + * Denotes a macro substitute method. This replaces a method invocation with an instance of the + * specified node class. + * + * A macro substitution can be combined with a normal substitution, so that the macro node can + * be replaced with the actual substitution code during lowering. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface MacroSubstitution { + + /** + * Gets the name of the substituted method. + *

+ * If the default value is specified for this element, then the name of the substituted + * method is same as the substitute method. + */ + String value() default ""; + + /** + * Determines if the substituted method is static. + */ + boolean isStatic() default true; + + /** + * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the substituted + * method. + *

+ * If the default value is specified for this element, then the signature of the substituted + * method is the same as the substitute method. + */ + String signature() default ""; + + /** + * The node class with which the method invocation should be replaced. It needs to be a + * subclass of {@link FixedWithNextNode}, and it is expected to provide a public constructor + * that takes an InvokeNode as a parameter. For most cases this class should subclass + * {@link MacroNode} and use its constructor. + */ + Class macro(); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, 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.nodes.calc.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link java.lang.Double} methods. + */ +@ClassSubstitution(java.lang.Double.class) +public class DoubleSubstitutions { + + private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN); + + @MethodSubstitution + public static long doubleToRawLongBits(double value) { + @JavacBug(id = 6995200) + Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value); + return result; + } + + // TODO This method is not necessary, since the JDK method does exactly this + @MethodSubstitution + public static long doubleToLongBits(double value) { + if (value != value) { + return NAN_RAW_LONG_BITS; + } else { + return doubleToRawLongBits(value); + } + } + + @MethodSubstitution + public static double longBitsToDouble(long bits) { + @JavacBug(id = 6995200) + Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits); + return result; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, 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.nodes.calc.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link java.lang.Float} methods. + */ +@ClassSubstitution(java.lang.Float.class) +public class FloatSubstitutions { + + private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN); + + @MethodSubstitution + public static int floatToRawIntBits(float value) { + @JavacBug(id = 6995200) + Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value); + return result; + } + + // TODO This method is not necessary, since the JDK method does exactly this + @MethodSubstitution + public static int floatToIntBits(float value) { + if (value != value) { + return NAN_RAW_INT_BITS; + } else { + return floatToRawIntBits(value); + } + } + + @MethodSubstitution + public static float intBitsToFloat(int bits) { + @JavacBug(id = 6995200) + Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits); + return result; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalIntrinsics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalIntrinsics.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011, 2011, 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.phases.*; + +/** + * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. + */ +public class GraalIntrinsics { + + public static void installIntrinsics(ReplacementsInstaller installer) { + if (GraalOptions.Intrinsify) { + installer.installSubstitutions(MathSubstitutionsX86.class); + installer.installSubstitutions(DoubleSubstitutions.class); + installer.installSubstitutions(FloatSubstitutions.class); + installer.installSubstitutions(NodeClassSubstitutions.class); + installer.installSubstitutions(LongSubstitutions.class); + installer.installSubstitutions(IntegerSubstitutions.class); + installer.installSubstitutions(UnsignedMathSubstitutions.class); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2012, 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 static com.oracle.graal.nodes.calc.CompareNode.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.replacements.SnippetTemplate.*; + +/** + * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity + * in such a lowering derives from the fact that {@link InstanceOfNode} is a floating node. A + * snippet used to lower an {@link InstanceOfNode} will almost always incorporate control flow and + * replacing a floating node with control flow is not trivial. + *

+ * The mechanism implemented in this class ensures that the graph for an instanceof snippet is + * instantiated once per {@link InstanceOfNode} being lowered. The result produced is then re-used + * by all usages of the node. Additionally, if there is a single usage that is an {@link IfNode}, + * the control flow in the snippet is connected directly to the true and false successors of the + * {@link IfNode}. This avoids materializing the instanceof test as a boolean which is then retested + * by the {@link IfNode}. + */ +public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates { + + public InstanceOfSnippetsTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { + super(runtime, assumptions, target, snippetsClass); + } + + /** + * The key and arguments used to retrieve and instantiate an instanceof snippet template. + */ + public static class KeyAndArguments { + + public final Key key; + public final Arguments arguments; + + public KeyAndArguments(Key key, Arguments arguments) { + this.key = key; + this.arguments = arguments; + } + + } + + /** + * Gets the key and arguments used to retrieve and instantiate an instanceof snippet template. + */ + protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); + + public void lower(FloatingNode instanceOf, LoweringTool tool) { + assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; + List usages = instanceOf.usages().snapshot(); + int nUsages = usages.size(); + + Instantiation instantiation = new Instantiation(); + for (Node usage : usages) { + final StructuredGraph graph = (StructuredGraph) usage.graph(); + + InstanceOfUsageReplacer replacer = createReplacer(instanceOf, tool, nUsages, instantiation, usage, graph); + + if (instantiation.isInitialized()) { + // No need to re-instantiate the snippet - just re-use its result + replacer.replaceUsingInstantiation(); + } else { + KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool); + SnippetTemplate template = cache.get(keyAndArguments.key, assumptions); + template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments); + } + } + + assert instanceOf.usages().isEmpty(); + if (!instanceOf.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(instanceOf); + } + } + + /** + * Gets the specific replacer object used to replace the usage of an instanceof node with the + * result of an instantiated instanceof snippet. + */ + protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { + InstanceOfUsageReplacer replacer; + if (usage instanceof IfNode) { + replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool); + } else { + assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; + ConditionalNode c = (ConditionalNode) usage; + replacer = new ConditionalUsageReplacer(instantiation, c.trueValue(), c.falseValue(), instanceOf, c); + } + return replacer; + } + + /** + * The result of an instantiating an instanceof snippet. This enables a snippet instantiation to + * be re-used which reduces compile time and produces better code. + */ + public static final class Instantiation { + + private PhiNode result; + private CompareNode condition; + private ValueNode trueValue; + private ValueNode falseValue; + + /** + * Determines if the instantiation has occurred. + */ + boolean isInitialized() { + return result != null; + } + + void initialize(PhiNode phi, ValueNode t, ValueNode f) { + assert !isInitialized(); + this.result = phi; + this.trueValue = t; + this.falseValue = f; + } + + /** + * Gets the result of this instantiation as a condition. + * + * @param testValue the returned condition is true if the result is equal to this value + */ + CompareNode asCondition(ValueNode testValue) { + assert isInitialized(); + if (condition == null || condition.y() != testValue) { + // Re-use previously generated condition if the trueValue for the test is the same + condition = createCompareNode(Condition.EQ, result, testValue); + } + return condition; + } + + /** + * Gets the result of the instantiation as a materialized value. + * + * @param t the true value for the materialization + * @param f the false value for the materialization + */ + ValueNode asMaterialization(ValueNode t, ValueNode f) { + assert isInitialized(); + if (t == this.trueValue && f == this.falseValue) { + // Can simply use the phi result if the same materialized values are expected. + return result; + } else { + return t.graph().unique(new ConditionalNode(asCondition(trueValue), t, f)); + } + } + } + + /** + * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. + */ + public abstract static class InstanceOfUsageReplacer implements UsageReplacer { + + public final Instantiation instantiation; + public final FloatingNode instanceOf; + public final ValueNode trueValue; + public final ValueNode falseValue; + + public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) { + assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; + this.instantiation = instantiation; + this.instanceOf = instanceOf; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + /** + * Does the replacement based on a previously snippet instantiation. + */ + public abstract void replaceUsingInstantiation(); + } + + /** + * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or + * {@link InstanceOfDynamicNode}. + */ + public static class IfUsageReplacer extends InstanceOfUsageReplacer { + + private final boolean solitaryUsage; + private final IfNode usage; + private final boolean sameBlock; + + public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) { + super(instantiation, instanceOf, trueValue, falseValue); + this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf); + this.solitaryUsage = solitaryUsage; + this.usage = usage; + } + + @Override + public void replaceUsingInstantiation() { + usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue)); + } + + private boolean usageFollowsInstantiation() { + return instantiation.result != null && instantiation.result.merge().next() == usage; + } + + @Override + public void replace(ValueNode oldNode, ValueNode newNode) { + assert newNode instanceof PhiNode; + assert oldNode == instanceOf; + if (sameBlock && solitaryUsage && usageFollowsInstantiation()) { + removeIntermediateMaterialization(newNode); + } else { + newNode.inferStamp(); + instantiation.initialize((PhiNode) newNode, trueValue, falseValue); + usage.replaceFirstInput(oldNode, instantiation.asCondition(trueValue)); + } + } + + /** + * Directly wires the incoming edges of the merge at the end of the snippet to the outgoing + * edges of the IfNode that uses the materialized result. + */ + private void removeIntermediateMaterialization(ValueNode newNode) { + IfNode ifNode = usage; + PhiNode phi = (PhiNode) newNode; + MergeNode merge = phi.merge(); + assert merge.stateAfter() == null; + + List mergePredecessors = merge.cfgPredecessors().snapshot(); + assert phi.valueCount() == mergePredecessors.size(); + + List falseEnds = new ArrayList<>(mergePredecessors.size()); + List trueEnds = new ArrayList<>(mergePredecessors.size()); + + int endIndex = 0; + for (EndNode end : mergePredecessors) { + ValueNode endValue = phi.valueAt(endIndex++); + if (endValue == trueValue) { + trueEnds.add(end); + } else { + assert endValue == falseValue; + falseEnds.add(end); + } + } + + BeginNode trueSuccessor = ifNode.trueSuccessor(); + BeginNode falseSuccessor = ifNode.falseSuccessor(); + ifNode.setTrueSuccessor(null); + ifNode.setFalseSuccessor(null); + + connectEnds(merge, trueEnds, trueSuccessor); + connectEnds(merge, falseEnds, falseSuccessor); + + GraphUtil.killCFG(merge); + GraphUtil.killCFG(ifNode); + + assert !merge.isAlive() : merge; + assert !phi.isAlive() : phi; + } + + private static void connectEnds(MergeNode merge, List ends, BeginNode successor) { + if (ends.size() == 0) { + // InstanceOf has been lowered to always true or always false - this successor is + // therefore unreachable. + GraphUtil.killCFG(successor); + } else if (ends.size() == 1) { + EndNode end = ends.get(0); + ((FixedWithNextNode) end.predecessor()).setNext(successor); + merge.removeEnd(end); + GraphUtil.killCFG(end); + } else { + assert ends.size() > 1; + MergeNode newMerge = merge.graph().add(new MergeNode()); + + for (EndNode end : ends) { + newMerge.addForwardEnd(end); + } + newMerge.setNext(successor); + } + } + } + + /** + * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or + * {@link InstanceOfDynamicNode}. + */ + public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer { + + public final ConditionalNode usage; + + public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) { + super(instantiation, instanceOf, trueValue, falseValue); + this.usage = usage; + } + + @Override + public void replaceUsingInstantiation() { + ValueNode newValue = instantiation.asMaterialization(trueValue, falseValue); + usage.replaceAtUsages(newValue); + usage.clearInputs(); + assert usage.usages().isEmpty(); + GraphUtil.killWithUnusedFloatingInputs(usage); + } + + @Override + public void replace(ValueNode oldNode, ValueNode newNode) { + assert newNode instanceof PhiNode; + assert oldNode == instanceOf; + newNode.inferStamp(); + instantiation.initialize((PhiNode) newNode, trueValue, falseValue); + usage.replaceAtUsages(newNode); + usage.clearInputs(); + assert usage.usages().isEmpty(); + GraphUtil.killWithUnusedFloatingInputs(usage); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, 2012, 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.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +@ClassSubstitution(Integer.class) +public class IntegerSubstitutions { + + @MethodSubstitution + public static int reverseBytes(int i) { + return ReverseBytesNode.reverse(i); + } + + @MethodSubstitution + public static int numberOfLeadingZeros(int i) { + if (i == 0) { + return 32; + } + return 31 - BitScanReverseNode.scan(i); + } + + @MethodSubstitution + public static int numberOfTrailingZeros(int i) { + if (i == 0) { + return 32; + } + return BitScanForwardNode.scan(i); + } + + @MethodSubstitution + public static int bitCount(int i) { + return BitCountNode.bitCount(i); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/JavacBug.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/JavacBug.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, 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; + +/** + * Used to indicate that an otherwise strange looking code pattern is required to work around a bug + * in javac. + */ +public @interface JavacBug { + + /** + * A description of the bug. Only really useful if there is no existing entry for the bug in the + * Bug Database. + */ + String value() default ""; + + /** + * An identifier in the Bug Database. + */ + int id() default 0; +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2012, 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 java.io.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; + +//JaCoCo Exclude + +/** + * Provides {@link PrintStream}-like logging facility. This should only be used in + * {@linkplain Snippet snippets}. + */ +public final class Log { + + public static final Descriptor LOG_PRIMITIVE = new Descriptor("logPrimitive", false, void.class, int.class, long.class, boolean.class); + public static final Descriptor LOG_OBJECT = new Descriptor("logObject", false, void.class, Object.class, int.class); + public static final Descriptor LOG_PRINTF = new Descriptor("logPrintf", false, void.class, Object.class, long.class, long.class, long.class); + + // Note: Must be kept in sync with constants in c1_Runtime1.hpp + private static final int LOG_OBJECT_NEWLINE = 0x01; + private static final int LOG_OBJECT_STRING = 0x02; + private static final int LOG_OBJECT_ADDRESS = 0x04; + + @NodeIntrinsic(RuntimeCallNode.class) + private static native void log(@ConstantNodeParameter Descriptor logObject, Object object, int flags); + + @NodeIntrinsic(RuntimeCallNode.class) + private static native void log(@ConstantNodeParameter Descriptor logPrimitive, int typeChar, long value, boolean newline); + + @NodeIntrinsic(RuntimeCallNode.class) + private static native void printf(@ConstantNodeParameter Descriptor logPrintf, String format, long v1, long v2, long v3); + + public static void print(boolean value) { + log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, false); + } + + public static void print(byte value) { + log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, false); + } + + public static void print(char value) { + log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, false); + } + + public static void print(short value) { + log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, false); + } + + public static void print(int value) { + log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, false); + } + + public static void print(long value) { + log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, false); + } + + /** + * Prints a formatted string to the log stream. + * + * @param format a C style printf format value that can contain at most one conversion specifier + * (i.e., a sequence of characters starting with '%'). + * @param value the value associated with the conversion specifier + */ + public static void printf(String format, long value) { + printf(LOG_PRINTF, format, value, 0L, 0L); + } + + public static void printf(String format, long v1, long v2) { + printf(LOG_PRINTF, format, v1, v2, 0L); + } + + public static void printf(String format, long v1, long v2, long v3) { + printf(LOG_PRINTF, format, v1, v2, v3); + } + + public static void print(float value) { + if (Float.isNaN(value)) { + print("NaN"); + } else if (value == Float.POSITIVE_INFINITY) { + print("Infinity"); + } else if (value == Float.NEGATIVE_INFINITY) { + print("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), false); + } + } + + public static void print(double value) { + if (Double.isNaN(value)) { + print("NaN"); + } else if (value == Double.POSITIVE_INFINITY) { + print("Infinity"); + } else if (value == Double.NEGATIVE_INFINITY) { + print("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false); + } + } + + public static void print(String value) { + log(LOG_OBJECT, value, LOG_OBJECT_STRING); + } + + public static void printAddress(Object o) { + log(LOG_OBJECT, o, LOG_OBJECT_ADDRESS); + } + + public static void printObject(Object o) { + log(LOG_OBJECT, o, 0); + } + + public static void println(boolean value) { + log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, true); + } + + public static void println(byte value) { + log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, true); + } + + public static void println(char value) { + log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, true); + } + + public static void println(short value) { + log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, true); + } + + public static void println(int value) { + log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, true); + } + + public static void println(long value) { + log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, true); + } + + public static void println(float value) { + if (Float.isNaN(value)) { + println("NaN"); + } else if (value == Float.POSITIVE_INFINITY) { + println("Infinity"); + } else if (value == Float.NEGATIVE_INFINITY) { + println("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), true); + } + } + + public static void println(double value) { + if (Double.isNaN(value)) { + println("NaN"); + } else if (value == Double.POSITIVE_INFINITY) { + println("Infinity"); + } else if (value == Double.NEGATIVE_INFINITY) { + println("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true); + } + } + + public static void println(String value) { + log(LOG_OBJECT, value, LOG_OBJECT_NEWLINE | LOG_OBJECT_STRING); + } + + public static void printlnAddress(Object o) { + log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE | LOG_OBJECT_ADDRESS); + } + + public static void printlnObject(Object o) { + log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE); + } + + public static void println() { + println(""); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, 2012, 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.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +@ClassSubstitution(Long.class) +public class LongSubstitutions { + + @MethodSubstitution + public static long reverseBytes(long i) { + return ReverseBytesNode.reverse(i); + } + + @MethodSubstitution + public static int numberOfLeadingZeros(long i) { + if (i == 0) { + return 64; + } + return 63 - BitScanReverseNode.scan(i); + } + + @MethodSubstitution + public static int numberOfTrailingZeros(long i) { + if (i == 0) { + return 64; + } + return BitScanForwardNode.scan(i); + } + + @MethodSubstitution + public static int bitCount(long i) { + return BitCountNode.bitCount(i); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011, 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.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.replacements.nodes.MathIntrinsicNode.*; + +/** + * Substitutions for {@link java.lang.Math} methods. + */ +@ClassSubstitution(java.lang.Math.class) +public class MathSubstitutionsX86 { + + private static final double PI_4 = 0.7853981633974483; + + @MethodSubstitution + public static double abs(double x) { + return MathIntrinsicNode.compute(x, Operation.ABS); + } + + @MethodSubstitution + public static double sqrt(double x) { + return MathIntrinsicNode.compute(x, Operation.SQRT); + } + + @MethodSubstitution + public static double log(double x) { + return MathIntrinsicNode.compute(x, Operation.LOG); + } + + @MethodSubstitution + public static double log10(double x) { + return MathIntrinsicNode.compute(x, Operation.LOG10); + } + + // NOTE on snippets below: + // Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the + // exact result, but x87 trigonometric FPU instructions are only that + // accurate within [-pi/4, pi/4]. Examine the passed value and provide + // a slow path for inputs outside of that interval. + + @MethodSubstitution + public static double sin(double x) { + if (abs(x) < PI_4) { + return MathIntrinsicNode.compute(x, Operation.SIN); + } else { + return callDouble(ARITHMETIC_SIN, x); + } + } + + @MethodSubstitution + public static double cos(double x) { + if (abs(x) < PI_4) { + return MathIntrinsicNode.compute(x, Operation.COS); + } else { + return callDouble(ARITHMETIC_COS, x); + } + } + + @MethodSubstitution + public static double tan(double x) { + if (abs(x) < PI_4) { + return MathIntrinsicNode.compute(x, Operation.TAN); + } else { + return callDouble(ARITHMETIC_TAN, x); + } + } + + public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class); + public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class); + public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class); + + @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) + public static native double callDouble(@ConstantNodeParameter Descriptor descriptor, double value); +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 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.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for improving the performance of some critical methods in {@link NodeClass} + * methods. These substitutions improve the performance by forcing the relevant methods to be + * inlined (intrinsification being a special form of inlining) and removing a checked cast. The + * latter cannot be done directly in Java code as {@link UnsafeCastNode} is not available to the + * project containing {@link NodeClass}. + */ +@ClassSubstitution(NodeClass.class) +public class NodeClassSubstitutions { + + @MethodSubstitution + private static Node getNode(Node node, long offset) { + return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false); + } + + @MethodSubstitution + private static NodeList getNodeList(Node node, long offset) { + return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false); + } + + @MethodSubstitution + private static void putNode(Node node, long offset, Node value) { + UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); + } + + @MethodSubstitution + private static void putNodeList(Node node, long offset, NodeList value) { + UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); + } + +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2011, 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 static com.oracle.graal.api.meta.MetaUtil.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with + * {@link Fold} with the result of invoking the annotated method via reflection. + */ +public class NodeIntrinsificationPhase extends Phase { + + private final MetaAccessProvider runtime; + private final BoxingMethodPool pool; + + public NodeIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { + this.runtime = runtime; + this.pool = pool; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke i : graph.getInvokes()) { + if (i.callTarget() instanceof MethodCallTargetNode) { + tryIntrinsify(i); + } + } + } + + public static Class[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) { + int count = signature.getParameterCount(false); + Class[] result = new Class[count]; + for (int i = 0; i < result.length; ++i) { + result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); + } + return result; + } + + private boolean tryIntrinsify(Invoke invoke) { + ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); + NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); + ResolvedJavaType declaringClass = target.getDeclaringClass(); + if (intrinsic != null) { + assert target.getAnnotation(Fold.class) == null; + + Class[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); + ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass); + + // Prepare the arguments for the reflective constructor call on the node class. + Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); + if (nodeConstructorArguments == null) { + return false; + } + + // Create the new node instance. + Class c = getNodeClass(target, intrinsic); + Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments); + + // Replace the invoke with the new node. + invoke.node().graph().add(newInstance); + invoke.intrinsify(newInstance); + + // Clean up checkcast instructions inserted by javac if the return type is generic. + cleanUpReturnCheckCast(newInstance); + } else if (target.getAnnotation(Fold.class) != null) { + Class[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); + + // Prepare the arguments for the reflective method call + Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); + if (arguments == null) { + return false; + } + Object receiver = null; + if (!invoke.methodCallTarget().isStatic()) { + receiver = arguments[0]; + arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); + } + + // Call the method + Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, Thread.currentThread().getContextClassLoader()), target.getName(), parameterTypes, + receiver, arguments); + + if (constant != null) { + // Replace the invoke with the result of the call + ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.node().graph()); + invoke.intrinsify(node); + + // Clean up checkcast instructions inserted by javac if the return type is generic. + cleanUpReturnCheckCast(node); + } else { + // Remove the invoke + invoke.intrinsify(null); + } + } + return true; + } + + /** + * Converts the arguments of an invoke node to object values suitable for use as the arguments + * to a reflective invocation of a Java constructor or method. + * + * @param folding specifies if the invocation is for handling a {@link Fold} annotation + * @return the arguments for the reflective invocation or null if an argument of {@code invoke} + * that is expected to be constant isn't + */ + private Object[] prepareArguments(Invoke invoke, Class[] parameterTypes, ResolvedJavaMethod target, boolean folding) { + NodeInputList arguments = invoke.callTarget().arguments(); + Object[] reflectionCallArguments = new Object[arguments.size()]; + for (int i = 0; i < reflectionCallArguments.length; ++i) { + int parameterIndex = i; + if (!invoke.methodCallTarget().isStatic()) { + parameterIndex--; + } + ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); + if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { + if (!(argument instanceof ConstantNode)) { + return null; + } + ConstantNode constantNode = (ConstantNode) argument; + Constant constant = constantNode.asConstant(); + Object o = constant.asBoxedValue(); + if (o instanceof Class) { + reflectionCallArguments[i] = runtime.lookupJavaType((Class) o); + parameterTypes[i] = ResolvedJavaType.class; + } else { + if (parameterTypes[i] == boolean.class) { + reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); + } else if (parameterTypes[i] == byte.class) { + reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); + } else if (parameterTypes[i] == short.class) { + reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); + } else if (parameterTypes[i] == char.class) { + reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); + } else { + reflectionCallArguments[i] = o; + } + } + } else { + reflectionCallArguments[i] = argument; + parameterTypes[i] = ValueNode.class; + } + } + return reflectionCallArguments; + } + + private static Class getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { + Class result = intrinsic.value(); + if (result == NodeIntrinsic.class) { + return getMirrorOrFail(target.getDeclaringClass(), Thread.currentThread().getContextClassLoader()); + } + assert Node.class.isAssignableFrom(result); + return result; + } + + private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) { + if (parameterIndex >= 0) { + Type type = target.getGenericParameterTypes()[parameterIndex]; + if (type instanceof TypeVariable) { + TypeVariable typeVariable = (TypeVariable) type; + if (typeVariable.getBounds().length == 1) { + Type boundType = typeVariable.getBounds()[0]; + if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) { + // Unbound generic => try boxing elimination + if (node.usages().count() == 2) { + if (node instanceof Invoke) { + Invoke invokeNode = (Invoke) node; + MethodCallTargetNode callTarget = invokeNode.methodCallTarget(); + if (pool.isBoxingMethod(callTarget.targetMethod())) { + FrameState stateAfter = invokeNode.stateAfter(); + assert stateAfter.usages().count() == 1; + invokeNode.node().replaceAtUsages(null); + ValueNode result = callTarget.arguments().get(0); + StructuredGraph graph = (StructuredGraph) node.graph(); + if (invokeNode instanceof InvokeWithExceptionNode) { + // Destroy exception edge & clear stateAfter. + InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; + + invokeWithExceptionNode.killExceptionEdge(); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); + } else { + graph.removeFixed((InvokeNode) invokeNode); + } + stateAfter.safeDelete(); + GraphUtil.propagateKill(callTarget); + return result; + } + } + } + } + } + } + } + return node; + } + + private static Class asBoxedType(Class type) { + if (!type.isPrimitive()) { + return type; + } + + if (Boolean.TYPE == type) { + return Boolean.class; + } + if (Character.TYPE == type) { + return Character.class; + } + if (Byte.TYPE == type) { + return Byte.class; + } + if (Short.TYPE == type) { + return Short.class; + } + if (Integer.TYPE == type) { + return Integer.class; + } + if (Long.TYPE == type) { + return Long.class; + } + if (Float.TYPE == type) { + return Float.class; + } + assert Double.TYPE == type; + return Double.class; + } + + static final int VARARGS = 0x00000080; + + private static Node createNodeInstance(Class nodeClass, Class[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Object[] nodeConstructorArguments) { + Object[] arguments = null; + Constructor constructor = null; + nextConstructor: for (Constructor c : nodeClass.getDeclaredConstructors()) { + Class[] signature = c.getParameterTypes(); + if ((c.getModifiers() & VARARGS) != 0) { + int fixedArgs = signature.length - 1; + if (parameterTypes.length < fixedArgs) { + continue nextConstructor; + } + + for (int i = 0; i < fixedArgs; i++) { + if (!parameterTypes[i].equals(signature[i])) { + continue nextConstructor; + } + } + + Class componentType = signature[fixedArgs].getComponentType(); + assert componentType != null : "expected last parameter of varargs constructor " + c + " to be an array type"; + Class boxedType = asBoxedType(componentType); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + if (!boxedType.isInstance(nodeConstructorArguments[i])) { + continue nextConstructor; + } + } + + arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); + int varargsLength = nodeConstructorArguments.length - fixedArgs; + Object varargs = Array.newInstance(componentType, varargsLength); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]); + } + arguments[fixedArgs] = varargs; + constructor = c; + break; + } else if (Arrays.equals(parameterTypes, signature)) { + arguments = nodeConstructorArguments; + constructor = c; + break; + } + } + if (constructor == null) { + throw new GraalInternalError("Could not find constructor in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes)); + } + constructor.setAccessible(true); + try { + ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments); + if (setStampFromReturnType) { + if (returnType.getKind() == Kind.Object) { + intrinsicNode.setStamp(StampFactory.declared(returnType)); + } else { + intrinsicNode.setStamp(StampFactory.forKind(returnType.getKind())); + } + } + return intrinsicNode; + } catch (Exception e) { + throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); + } + } + + /** + * Calls a Java method via reflection. + */ + private static Constant callMethod(Kind returnKind, Class holder, String name, Class[] parameterTypes, Object receiver, Object[] arguments) { + Method method; + try { + method = holder.getDeclaredMethod(name, parameterTypes); + method.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Object result = method.invoke(receiver, arguments); + if (result == null) { + return null; + } + return Constant.forBoxed(returnKind, result); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String sourceLocation(Node n) { + String loc = GraphUtil.approxSourceLocation(n); + return loc == null ? "" : loc; + } + + public void cleanUpReturnCheckCast(Node newInstance) { + if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { + StructuredGraph graph = (StructuredGraph) newInstance.graph(); + for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { + for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) { + graph.replaceFloating(vpn, checkCastNode); + } + for (Node checkCastUsage : checkCastNode.usages().snapshot()) { + if (checkCastUsage instanceof ValueAnchorNode) { + ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; + graph.removeFixed(valueAnchorNode); + } else if (checkCastUsage instanceof MethodCallTargetNode) { + MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; + if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) { + Invoke invokeNode = checkCastCallTarget.invoke(); + invokeNode.node().replaceAtUsages(newInstance); + if (invokeNode instanceof InvokeWithExceptionNode) { + // Destroy exception edge & clear stateAfter. + InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; + + invokeWithExceptionNode.killExceptionEdge(); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); + } else { + graph.removeFixed((InvokeNode) invokeNode); + } + checkCastCallTarget.safeDelete(); + } else { + assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + + " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + + checkCastCallTarget.targetMethod(); + checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); + } + } else if (checkCastUsage instanceof FrameState) { + checkCastUsage.replaceFirstInput(checkCastNode, null); + } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { + checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); + } else { + assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); + } + } + FixedNode next = checkCastNode.next(); + checkCastNode.setNext(null); + checkCastNode.replaceAtPredecessor(next); + GraphUtil.killCFG(checkCastNode); + } + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, 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.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods. + */ +public class NodeIntrinsificationVerificationPhase extends Phase { + + public static boolean verify(StructuredGraph graph) { + new NodeIntrinsificationVerificationPhase().apply(graph); + return true; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke i : graph.getInvokes()) { + if (i.callTarget() instanceof MethodCallTargetNode) { + checkInvoke(i); + } + } + } + + private static void checkInvoke(Invoke invoke) { + ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); + NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); + if (intrinsic != null) { + throw new GraalInternalError("Illegal call to node intrinsic in " + invoke.graph() + ": " + invoke); + } else if (target.getAnnotation(Fold.class) != null) { + throw new GraalInternalError("Illegal call to foldable method in " + invoke.graph() + ": " + invoke); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsInstaller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsInstaller.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2011, 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 static com.oracle.graal.api.meta.MetaUtil.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.phases.*; + +/** + * Utility for managing the pre-processing and installation of replacements. Replacements are either + * {@linkplain Snippets snippets}, {@linkplain MethodSubstitution method substitutions} or + * {@link MacroSubstitution macro substitutions}. + */ +public class ReplacementsInstaller { + + protected final MetaAccessProvider runtime; + protected final TargetDescription target; + protected final Assumptions assumptions; + protected final BoxingMethodPool pool; + private final Thread owner; + + /** + * A graph cache used by this installer to avoid using the compiler storage for each method + * processed during snippet installation. Without this, all processed methods are to be + * determined as {@linkplain InliningUtil#canIntrinsify intrinsifiable}. + */ + private final Map graphCache; + + public ReplacementsInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { + this.runtime = runtime; + this.target = target; + this.assumptions = assumptions; + this.pool = new BoxingMethodPool(runtime); + this.graphCache = new HashMap<>(); + this.owner = Thread.currentThread(); + } + + /** + * Finds all the snippet methods in a given class, builds a graph for them and installs the + * graph with the key value of {@code Graph.class} in the + * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. + */ + public void installSnippets(Class snippets) { + for (Method method : snippets.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null) { + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); + assert snippet.getCompilerStorage().get(Graph.class) == null : method; + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + // System.out.println("snippet: " + graph); + snippet.getCompilerStorage().put(Graph.class, graph); + } + } + } + + /** + * Finds all the methods in a given class annotated with {@link MethodSubstitution} or + * {@link MacroSubstitution}. It builds graphs for the former and installs them in the + * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of the original (i.e., + * substituted) method with a key of {@code Graph.class}. For the latter, the denoted + * {@linkplain MacroSubstitution#macro() macro} node type is install in the compiler storage + * with a key of {@code Node.class}. + */ + public void installSubstitutions(Class substitutions) { + assert owner == Thread.currentThread() : "substitution installation must be single threaded"; + ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); + assert classSubstitution != null; + assert !Snippets.class.isAssignableFrom(substitutions); + for (Method substituteMethod : substitutions.getDeclaredMethods()) { + MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); + MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); + if (methodSubstitution == null && macroSubstitution == null) { + continue; + } + + int modifiers = substituteMethod.getModifiers(); + if (!Modifier.isStatic(modifiers)) { + throw new RuntimeException("Substitution methods must be static: " + substituteMethod); + } + + if (methodSubstitution != null) { + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod); + } + String originalName = originalName(substituteMethod, methodSubstitution.value()); + Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); + if (originalMethod != null) { + installMethodSubstitution(originalMethod, substituteMethod); + } + } + if (macroSubstitution != null) { + String originalName = originalName(substituteMethod, macroSubstitution.value()); + Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); + if (originalMethod != null) { + installMacroSubstitution(originalMethod, macroSubstitution.macro()); + } + } + } + } + + // These fields are used to detect calls from the substitute method to the original method. + ResolvedJavaMethod substitute; + ResolvedJavaMethod original; + boolean substituteCallsOriginal; + + /** + * Installs a method substitution. + * + * @param originalMethod a method or constructor being substituted + * @param substituteMethod the substitute method + */ + protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { + substitute = runtime.lookupJavaMethod(substituteMethod); + if (originalMethod instanceof Method) { + original = runtime.lookupJavaMethod((Method) originalMethod); + } else { + original = runtime.lookupJavaConstructor((Constructor) originalMethod); + } + try { + Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); + StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute)); + Object oldValue = original.getCompilerStorage().put(Graph.class, graph); + assert oldValue == null; + } finally { + substitute = null; + original = null; + substituteCallsOriginal = false; + } + } + + /** + * Installs a macro substitution. + * + * @param originalMethod a method or constructor being substituted + * @param macro the substitute macro node class + */ + protected void installMacroSubstitution(Member originalMethod, Class macro) { + ResolvedJavaMethod originalJavaMethod; + if (originalMethod instanceof Method) { + originalJavaMethod = runtime.lookupJavaMethod((Method) originalMethod); + } else { + originalJavaMethod = runtime.lookupJavaConstructor((Constructor) originalMethod); + } + Object oldValue = originalJavaMethod.getCompilerStorage().put(Node.class, macro); + assert oldValue == null; + } + + private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { + Class policyClass = SnippetInliningPolicy.class; + Snippet snippet = method.getAnnotation(Snippet.class); + if (snippet != null) { + policyClass = snippet.inlining(); + } + if (policyClass == SnippetInliningPolicy.class) { + return new DefaultSnippetInliningPolicy(runtime, pool); + } + try { + return policyClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + /** + * Does final processing of a snippet graph. + */ + protected void finalizeGraph(ResolvedJavaMethod method, StructuredGraph graph) { + new NodeIntrinsificationPhase(runtime, pool).apply(graph); + assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); + + new SnippetFrameStateCleanupPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + + new InsertStateAfterPlaceholderPhase().apply(graph); + } + + public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable() { + + @Override + public StructuredGraph call() throws Exception { + StructuredGraph graph = parseGraph(method, policy); + + finalizeGraph(method, graph); + + Debug.dump(graph, "%s: Final", method.getName()); + + return graph; + } + }); + } + + private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + StructuredGraph graph = graphCache.get(method); + if (graph == null) { + graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); + graphCache.put(method, graph); + } + return graph; + } + + /** + * Builds the initial graph for a snippet. + */ + protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod method) { + final StructuredGraph graph = new StructuredGraph(method); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); + + Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); + + new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); + new NodeIntrinsificationPhase(runtime, pool).apply(graph); + + return graph; + } + + /** + * Called after a graph is inlined. + * + * @param caller the graph into which {@code callee} was inlined + * @param callee the graph that was inlined into {@code caller} + */ + protected void afterInline(StructuredGraph caller, StructuredGraph callee) { + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller); + new CanonicalizerPhase(runtime, assumptions).apply(caller); + } + } + + /** + * Called after all inlining for a given graph is complete. + */ + protected void afterInlining(StructuredGraph graph) { + new NodeIntrinsificationPhase(runtime, pool).apply(graph); + + new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); + + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(graph); + } + } + + private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : method; + final StructuredGraph graph = buildInitialGraph(method); + + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (callee == substitute) { + final StructuredGraph originalGraph = new StructuredGraph(original); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); + InliningUtil.inline(invoke, originalGraph, true); + + Debug.dump(graph, "after inlining %s", callee); + afterInline(graph, originalGraph); + substituteCallsOriginal = true; + } else { + if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) { + StructuredGraph targetGraph = parseGraph(callee, policy); + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); + afterInline(graph, targetGraph); + } + } + } + + afterInlining(graph); + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(graph); + new ComputeProbabilityPhase().apply(graph); + } + return graph; + } + + private static String originalName(Method substituteMethod, String methodSubstitution) { + if (methodSubstitution.isEmpty()) { + return substituteMethod.getName(); + } else { + return methodSubstitution; + } + } + + /** + * Resolves a name to a class. + * + * @param className the name of the class to resolve + * @param optional if true, resolution failure returns null + * @return the resolved class or null if resolution fails and {@code optional} is true + */ + private static Class resolveType(String className, boolean optional) { + try { + // Need to use launcher class path to handle classes + // that are not on the boot class path + ClassLoader cl = Launcher.getLauncher().getClassLoader(); + return Class.forName(className, false, cl); + } catch (ClassNotFoundException e) { + if (optional) { + return null; + } + throw new GraalInternalError("Could not resolve type " + className); + } + } + + private static Class resolveType(JavaType type) { + JavaType base = type; + int dimensions = 0; + while (base.getComponentType() != null) { + base = base.getComponentType(); + dimensions++; + } + + Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); + return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); + } + + private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) { + Class[] parameters; + if (methodSubstitution.isEmpty()) { + parameters = substituteMethod.getParameterTypes(); + if (!isStatic) { + assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; + parameters = Arrays.copyOfRange(parameters, 1, parameters.length); + } + } else { + Signature signature = runtime.parseMethodDescriptor(methodSubstitution); + parameters = new Class[signature.getParameterCount(false)]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = resolveType(signature.getParameterType(i, null)); + } + } + return parameters; + } + + private static Member originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { + Class originalClass = classSubstitution.value(); + if (originalClass == ClassSubstitution.class) { + originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); + if (originalClass == null) { + // optional class was not found + return null; + } + } + try { + if (name.equals("")) { + return originalClass.getDeclaredConstructor(parameters); + } else { + return originalClass.getDeclaredMethod(name, parameters); + } + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2011, 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 java.lang.annotation.*; +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +/** + * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering + * nodes that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode). + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Snippet { + + /** + * Specifies the class defining the inlining policy for this snippet. A + * {@linkplain DefaultSnippetInliningPolicy default} policy is used if none is supplied. + */ + Class inlining() default SnippetInliningPolicy.class; + + /** + * Guides inlining decisions used when installing a snippet. + */ + public interface SnippetInliningPolicy { + + /** + * Determines if {@code method} should be inlined into {@code caller}. + */ + boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); + } + + /** + * The default inlining policy which inlines everything except for methods in any of the + * following categories. + *

    + *
  • {@linkplain Fold foldable} methods
  • + *
  • {@linkplain NodeIntrinsic node intrinsics}
  • + *
  • native methods
  • + *
  • constructors of {@link Throwable} classes
  • + *
+ */ + public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { + + private final MetaAccessProvider metaAccess; + private final BoxingMethodPool pool; + + public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { + this.metaAccess = metaAccess; + this.pool = pool; + } + + @Override + public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { + if (Modifier.isNative(method.getModifiers())) { + return false; + } + if (method.getAnnotation(Fold.class) != null) { + return false; + } + if (method.getAnnotation(NodeIntrinsic.class) != null) { + return false; + } + if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { + if (method.getName().equals("")) { + return false; + } + } + if (method.getAnnotation(Word.Operation.class) != null) { + return false; + } + if (pool.isSpecialMethod(method)) { + return false; + } + return true; + } + } + + /** + * Annotates a method replaced by a compile-time constant. A (resolved) call to the annotated + * method is replaced with a constant obtained by calling the annotated method via reflection. + * + * All arguments to such a method (including the receiver if applicable) must be compile-time + * constants. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public static @interface Fold { + } + + /** + * Denotes a snippet parameter that will be bound during snippet template + * {@linkplain SnippetTemplate#instantiate instantiation}. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface Parameter { + + /** + * The name of this parameter. + */ + String value(); + } + + /** + * Denotes a snippet parameter representing 0 or more arguments that will be bound during + * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet + * template creation, its value must be an array whose length specifies the number of arguments + * (the contents of the array are ignored) bound to the parameter during + * {@linkplain SnippetTemplate#instantiate instantiation}. + * + * Such a parameter must be used in a counted loop in the snippet preceded by a call to + * {@link ExplodeLoopNode#explodeLoop()}. The counted looped must be a standard iteration over + * all the loop's elements (i.e. {@code for (T e : arr) ... }). + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface VarargsParameter { + + /** + * The name of this parameter. + */ + String value(); + } + + /** + * Denotes a snippet parameter that will bound to a constant value during snippet template + * {@linkplain SnippetTemplate#instantiate instantiation}. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface ConstantParameter { + + /** + * The name of this constant. + */ + String value(); + } + + /** + * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. + */ + public static class Varargs { + + private final Object args; + private final Class argType; + private final int length; + private final Stamp argStamp; + + public static Varargs vargargs(Object array, Stamp argStamp) { + return new Varargs(array, argStamp); + } + + public Varargs(Object array, Stamp argStamp) { + assert array != null; + this.argType = array.getClass().getComponentType(); + this.argStamp = argStamp; + assert this.argType != null; + this.length = java.lang.reflect.Array.getLength(array); + this.args = array; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Varargs) { + Varargs other = (Varargs) obj; + return other.argType == argType && other.length == length; + } + return false; + } + + public Object getArray() { + return args; + } + + public Stamp getArgStamp() { + return argStamp; + } + + @Override + public int hashCode() { + return argType.hashCode() ^ length; + } + + @Override + public String toString() { + return argType.getName() + "[" + length + "]"; + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2012, 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; + +//JaCoCo Exclude + +import static com.oracle.graal.graph.FieldIntrospection.*; + +import java.io.*; +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering + * snippet specific metrics. + */ +public class SnippetCounter implements Comparable { + + /** + * A group of related counters. + */ + public static class Group { + + final String name; + final List counters; + + public Group(String name) { + this.name = name; + this.counters = new ArrayList<>(); + } + + @Override + public synchronized String toString() { + Collections.sort(counters); + + long total = 0; + int maxNameLen = 0; + for (SnippetCounter c : counters) { + total += c.value; + maxNameLen = Math.max(c.name.length(), maxNameLen); + } + + StringBuilder buf = new StringBuilder(String.format("Counters: %s%n", name)); + + for (SnippetCounter c : counters) { + double percent = total == 0D ? 0D : ((double) (c.value * 100)) / total; + buf.append(String.format(" %" + maxNameLen + "s: %5.2f%%%10d // %s%n", c.name, percent, c.value, c.description)); + } + return buf.toString(); + } + } + + /** + * Sorts counters in descending order of their {@linkplain #value() values}. + */ + @Override + public int compareTo(SnippetCounter o) { + if (value > o.value) { + return -1; + } else if (o.value < value) { + return 1; + } + return 0; + } + + private static final List groups = new ArrayList<>(); + + private final Group group; + private final int index; + private final String name; + private final String description; + private long value; + + @Fold + private static int countOffset() { + try { + return (int) unsafe.objectFieldOffset(SnippetCounter.class.getDeclaredField("value")); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + /** + * Creates a counter. + * + * @param group the group to which the counter belongs. If this is null, the newly created + * counter is disabled and {@linkplain #inc() incrementing} is a no-op. + * @param name the name of the counter + * @param description a brief comment describing the metric represented by the counter + */ + public SnippetCounter(Group group, String name, String description) { + this.group = group; + this.name = name; + this.description = description; + if (group != null) { + List counters = group.counters; + this.index = counters.size(); + counters.add(this); + if (index == 0) { + groups.add(group); + } + } else { + this.index = -1; + } + } + + /** + * Increments the value of this counter. This method can be safely used in a snippet if it is + * invoked on a compile-time constant {@link SnippetCounter} object. + */ + public void inc() { + if (group != null) { + DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1); + } + } + + /** + * Gets the value of this counter. + */ + public long value() { + return value; + } + + /** + * Prints all the counter groups to a given stream. + */ + public static void printGroups(PrintStream out) { + for (Group group : groups) { + out.println(group); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011, 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 java.util.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; + +/** + * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a + * snippet. + * + * The frame states of side-effecting nodes are replaced with + * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid + * frame states are also assigned an invalid frame state. + * + * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. + */ +public class SnippetFrameStateCleanupPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); + } + + private static class CleanupState { + + public boolean containsFrameState; + + public CleanupState(boolean containsFrameState) { + this.containsFrameState = containsFrameState; + } + } + + /** + * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid + * frame states, so that they can be marked with an invalid frame state. + */ + private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure { + + @Override + protected void processNode(FixedNode node, CleanupState currentState) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + if (frameState != null) { + if (stateSplit.hasSideEffect()) { + currentState.containsFrameState = true; + stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } else { + stateSplit.setStateAfter(null); + } + if (frameState.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(frameState); + } + } + } + } + + @Override + protected CleanupState merge(MergeNode merge, List states) { + for (CleanupState state : states) { + if (state.containsFrameState) { + return new CleanupState(true); + } + } + return new CleanupState(false); + } + + @Override + protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { + return new CleanupState(oldState.containsFrameState); + } + + @Override + protected Map processLoop(LoopBeginNode loop, CleanupState initialState) { + LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); + boolean containsFrameState = false; + for (CleanupState state : info.endStates.values()) { + containsFrameState |= state.containsFrameState; + } + if (containsFrameState) { + loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } + if (containsFrameState || initialState.containsFrameState) { + for (CleanupState state : info.exitStates.values()) { + state.containsFrameState = true; + } + } + return info.exitStates; + } + + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2012, 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 java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.loop.*; +import com.oracle.graal.nodes.*; +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.common.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; +import com.oracle.graal.word.phases.*; + +/** + * A snippet template is a graph created by parsing a snippet method and then specialized by binding + * constants to the snippet's {@link ConstantParameter} parameters. + * + * Snippet templates can be managed in a {@link Cache}. + */ +public class SnippetTemplate { + + /** + * A snippet template key encapsulates the method from which a snippet was built and the + * arguments used to specialize the snippet. + * + * @see Cache + */ + public static class Key implements Iterable> { + + public final ResolvedJavaMethod method; + private final HashMap map = new HashMap<>(); + private int hash; + + public Key(ResolvedJavaMethod method) { + this.method = method; + this.hash = method.hashCode(); + } + + public Key add(String name, Object value) { + assert !map.containsKey(name); + map.put(name, value); + hash = hash ^ name.hashCode(); + if (value != null) { + hash *= (value.hashCode() + 1); + } + return this; + } + + public int length() { + return map.size(); + } + + public Object get(String name) { + return map.get(name); + } + + @Override + public Iterator> iterator() { + return map.entrySet().iterator(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Key) { + Key other = (Key) obj; + return other.method == method && other.map.equals(map); + } + return false; + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public String toString() { + return MetaUtil.format("%h.%n", method) + map.toString(); + } + + public Set names() { + return map.keySet(); + } + } + + /** + * Arguments used to instantiate a template. + */ + public static class Arguments implements Iterable> { + + private final HashMap map = new HashMap<>(); + + public static Arguments arguments(String name, Object value) { + return new Arguments().add(name, value); + } + + public Arguments add(String name, Object value) { + assert !map.containsKey(name); + map.put(name, value); + return this; + } + + public int length() { + return map.size(); + } + + @Override + public Iterator> iterator() { + return map.entrySet().iterator(); + } + + @Override + public String toString() { + return map.toString(); + } + } + + /** + * A collection of snippet templates accessed by a {@link Key} instance. + */ + public static class Cache { + + private final ConcurrentHashMap templates = new ConcurrentHashMap<>(); + private final MetaAccessProvider runtime; + private final TargetDescription target; + + public Cache(MetaAccessProvider runtime, TargetDescription target) { + this.runtime = runtime; + this.target = target; + } + + /** + * Gets a template for a given key, creating it first if necessary. + */ + public SnippetTemplate get(final SnippetTemplate.Key key, final Assumptions assumptions) { + SnippetTemplate template = templates.get(key); + if (template == null) { + template = Debug.scope("SnippetSpecialization", key.method, new Callable() { + + @Override + public SnippetTemplate call() throws Exception { + return new SnippetTemplate(runtime, assumptions, target, key); + } + }); + // System.out.println(key + " -> " + template); + templates.put(key, template); + } + return template; + } + } + + public abstract static class AbstractTemplates { + + protected final Cache cache; + protected final MetaAccessProvider runtime; + protected final Assumptions assumptions; + protected Class snippetsClass; + + public AbstractTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { + this.runtime = runtime; + this.assumptions = assumptions; + if (snippetsClass == null) { + assert this instanceof Snippets; + this.snippetsClass = getClass(); + } else { + this.snippetsClass = snippetsClass; + } + this.cache = new Cache(runtime, target); + } + + protected ResolvedJavaMethod snippet(String name, Class... parameterTypes) { + try { + ResolvedJavaMethod snippet = runtime.lookupJavaMethod(snippetsClass.getDeclaredMethod(name, parameterTypes)); + assert snippet.getAnnotation(Snippet.class) != null : "snippet is not annotated with @" + Snippet.class.getSimpleName(); + return snippet; + } catch (NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + } + + private static final Object UNUSED_PARAMETER = "DEAD PARAMETER"; + + /** + * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. + */ + public static boolean hasConstantParameter(ResolvedJavaMethod method) { + for (ConstantParameter p : MetaUtil.getParameterAnnotations(ConstantParameter.class, method)) { + if (p != null) { + return true; + } + } + return false; + } + + /** + * Creates a snippet template. + */ + public SnippetTemplate(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, SnippetTemplate.Key key) { + ResolvedJavaMethod method = key.method; + assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + method; + Signature signature = method.getSignature(); + + // Copy snippet graph, replacing constant parameters with given arguments + StructuredGraph snippetGraph = (StructuredGraph) method.getCompilerStorage().get(Graph.class); + StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); + IdentityHashMap replacements = new IdentityHashMap<>(); + replacements.put(snippetGraph.start(), snippetCopy.start()); + + int parameterCount = signature.getParameterCount(false); + assert checkTemplate(runtime, key, parameterCount, method, signature); + + Parameter[] parameterAnnotations = new Parameter[parameterCount]; + VarargsParameter[] varargsParameterAnnotations = new VarargsParameter[parameterCount]; + ConstantNode[] placeholders = new ConstantNode[parameterCount]; + for (int i = 0; i < parameterCount; i++) { + ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); + if (c != null) { + String name = c.value(); + Object arg = key.get(name); + Kind kind = signature.getParameterKind(i); + Constant constantArg; + if (arg instanceof Constant) { + constantArg = (Constant) arg; + } else { + constantArg = Constant.forBoxed(kind, arg); + } + replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); + } else { + VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); + if (vp != null) { + String name = vp.value(); + Varargs varargs = (Varargs) key.get(name); + Object array = varargs.getArray(); + ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); + replacements.put(snippetGraph.getLocal(i), placeholder); + placeholders[i] = placeholder; + varargsParameterAnnotations[i] = vp; + } else { + parameterAnnotations[i] = MetaUtil.getParameterAnnotation(Parameter.class, i, method); + } + } + } + snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); + + Debug.dump(snippetCopy, "Before specialization"); + if (!replacements.isEmpty()) { + // Do deferred intrinsification of node intrinsics + new NodeIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); + new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); + + new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy); + } + assert NodeIntrinsificationVerificationPhase.verify(snippetCopy); + + // Gather the template parameters + parameters = new HashMap<>(); + for (int i = 0; i < parameterCount; i++) { + VarargsParameter vp = varargsParameterAnnotations[i]; + if (vp != null) { + assert snippetCopy.getLocal(i) == null; + Varargs varargs = (Varargs) key.get(vp.value()); + Object array = varargs.getArray(); + int length = Array.getLength(array); + LocalNode[] locals = new LocalNode[length]; + Stamp stamp = varargs.getArgStamp(); + for (int j = 0; j < length; j++) { + assert (parameterCount & 0xFFFF) == parameterCount; + int idx = i << 16 | j; + LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); + locals[j] = local; + } + parameters.put(vp.value(), locals); + + ConstantNode placeholder = placeholders[i]; + assert placeholder != null; + for (Node usage : placeholder.usages().snapshot()) { + if (usage instanceof LoadIndexedNode) { + LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; + Debug.dump(snippetCopy, "Before replacing %s", loadIndexed); + LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(locals, loadIndexed.index(), loadIndexed.stamp())); + snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); + Debug.dump(snippetCopy, "After replacing %s", loadIndexed); + } + } + } else { + Parameter p = parameterAnnotations[i]; + if (p != null) { + LocalNode local = snippetCopy.getLocal(i); + if (local == null) { + // Parameter value was eliminated + parameters.put(p.value(), UNUSED_PARAMETER); + } else { + parameters.put(p.value(), local); + } + } + } + } + + // Do any required loop explosion + boolean exploded = false; + do { + exploded = false; + ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first(); + if (explodeLoop != null) { // Earlier canonicalization may have removed the loop + // altogether + LoopBeginNode loopBegin = explodeLoop.findLoopBegin(); + if (loopBegin != null) { + LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); + int mark = snippetCopy.getMark(); + LoopTransformations.fullUnroll(loop, runtime, null); + new CanonicalizerPhase(runtime, assumptions, mark, null).apply(snippetCopy); + } + FixedNode explodeLoopNext = explodeLoop.next(); + explodeLoop.clearSuccessors(); + explodeLoop.replaceAtPredecessor(explodeLoopNext); + explodeLoop.replaceAtUsages(null); + GraphUtil.killCFG(explodeLoop); + exploded = true; + } + } while (exploded); + + // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free + // of side-effects that prevent deoptimizing to a point before the snippet). + ArrayList curSideEffectNodes = new ArrayList<>(); + ArrayList curStampNodes = new ArrayList<>(); + for (Node node : snippetCopy.getNodes()) { + if (node instanceof ValueNode && ((ValueNode) node).stamp() == StampFactory.forNodeIntrinsic()) { + curStampNodes.add((ValueNode) node); + } + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + if (stateSplit.hasSideEffect()) { + curSideEffectNodes.add((StateSplit) node); + } + if (frameState != null) { + stateSplit.setStateAfter(null); + } + } + } + + new DeadCodeEliminationPhase().apply(snippetCopy); + + assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); + + this.snippet = snippetCopy; + ReturnNode retNode = null; + StartNode entryPointNode = snippet.start(); + + new DeadCodeEliminationPhase().apply(snippetCopy); + + nodes = new ArrayList<>(snippet.getNodeCount()); + for (Node node : snippet.getNodes()) { + if (node == entryPointNode || node == entryPointNode.stateAfter()) { + // Do nothing. + } else { + nodes.add(node); + if (node instanceof ReturnNode) { + retNode = (ReturnNode) node; + } + } + } + + this.sideEffectNodes = curSideEffectNodes; + this.stampNodes = curStampNodes; + this.returnNode = retNode; + } + + private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) { + for (int i = 0; i < parameterCount; i++) { + if (placeholders[i] != null) { + assert placeholders[i].isDeleted() : placeholders[i]; + } + } + return true; + } + + private static boolean checkConstantArgument(MetaAccessProvider runtime, final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) { + ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()); + if (runtime.lookupJavaType(WordBase.class).isAssignableFrom(type)) { + assert arg instanceof Constant : method + ": word constant parameters must be passed boxed in a Constant value: " + arg; + return true; + } + if (kind == Kind.Object) { + assert arg == null || type.isInstance(Constant.forObject(arg)) : method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName(); + } else { + assert arg != null && kind.toBoxedJavaClass() == arg.getClass() : method + ": wrong value kind for " + name + ": expected " + kind + ", got " + + (arg == null ? "null" : arg.getClass().getSimpleName()); + } + return true; + } + + private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { + Object arg = varargs.getArray(); + ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass()); + assert type.isArray() : "varargs parameter must be an array type"; + assert type.isInstance(Constant.forObject(arg)) : "value for " + name + " is not a " + MetaUtil.toJavaName(type) + " instance: " + arg; + return true; + } + + /** + * The graph built from the snippet method. + */ + private final StructuredGraph snippet; + + /** + * The named parameters of this template that must be bound to values during instantiation. For + * a parameter that is still live after specialization, the value in this map is either a + * {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter, the + * value is identical to the key. + */ + private final Map parameters; + + /** + * The return node (if any) of the snippet. + */ + private final ReturnNode returnNode; + + /** + * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during + * instantiation. + */ + private final ArrayList sideEffectNodes; + + /** + * The nodes that inherit the {@link ValueNode#stamp()} from the replacee during instantiation. + */ + private final ArrayList stampNodes; + + /** + * The nodes to be inlined when this specialization is instantiated. + */ + private final ArrayList nodes; + + /** + * Gets the instantiation-time bindings to this template's parameters. + * + * @return the map that will be used to bind arguments to parameters when inlining this template + */ + private IdentityHashMap bind(StructuredGraph replaceeGraph, MetaAccessProvider runtime, SnippetTemplate.Arguments args) { + IdentityHashMap replacements = new IdentityHashMap<>(); + assert args.length() == parameters.size() : "number of args (" + args.length() + ") != number of parameters (" + parameters.size() + ")"; + for (Map.Entry e : args) { + String name = e.getKey(); + Object parameter = parameters.get(name); + assert parameter != null : this + " has no parameter named " + name; + Object argument = e.getValue(); + if (parameter instanceof LocalNode) { + if (argument instanceof ValueNode) { + replacements.put((LocalNode) parameter, (ValueNode) argument); + } else { + Kind kind = ((LocalNode) parameter).kind(); + assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + name; + Constant constant = Constant.forBoxed(kind, argument); + replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); + } + } else if (parameter instanceof LocalNode[]) { + LocalNode[] locals = (LocalNode[]) parameter; + int length = locals.length; + List list = null; + Object array = null; + if (argument instanceof List) { + list = (List) argument; + assert list.size() == length : length + " != " + list.size(); + } else { + array = argument; + assert array != null && array.getClass().isArray(); + assert Array.getLength(array) == length : length + " != " + Array.getLength(array); + } + + for (int j = 0; j < length; j++) { + LocalNode local = locals[j]; + assert local != null; + Object value = list != null ? list.get(j) : Array.get(array, j); + if (value instanceof ValueNode) { + replacements.put(local, (ValueNode) value); + } else { + Constant constant = Constant.forBoxed(local.kind(), value); + ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); + replacements.put(local, element); + } + } + } else { + assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter; + } + } + return replacements; + } + + /** + * Logic for replacing a snippet-lowered node at its usages with the return value of the + * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default} + * replacement logic can be used to handle mismatches between the stamp of the node being + * lowered and the stamp of the snippet's return value. + */ + public interface UsageReplacer { + + /** + * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}. + */ + void replace(ValueNode oldNode, ValueNode newNode); + } + + /** + * Represents the default {@link UsageReplacer usage replacer} logic which simply delegates to + * {@link Node#replaceAtUsages(Node)}. + */ + public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() { + + @Override + public void replace(ValueNode oldNode, ValueNode newNode) { + oldNode.replaceAtUsages(newNode); + } + }; + + /** + * Replaces a given fixed node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param replacer object that replaces the usages of {@code replacee} + * @param args the arguments to be bound to the flattened positional parameters of the snippet + * @return the map of duplicated nodes (original -> duplicate) + */ + public Map instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap replacements = bind(replaceeGraph, runtime, args); + Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); + + // Re-wire the control flow graph around the replacee + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + replacee.replaceAtPredecessor(firstCFGNodeDuplicate); + FixedNode next = null; + if (replacee instanceof FixedWithNextNode) { + FixedWithNextNode fwn = (FixedWithNextNode) replacee; + next = fwn.next(); + fwn.setNext(null); + } + + if (replacee instanceof StateSplit) { + for (StateSplit sideEffectNode : sideEffectNodes) { + assert ((StateSplit) replacee).hasSideEffect(); + Node sideEffectDup = duplicates.get(sideEffectNode); + ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); + } + } + for (ValueNode stampNode : stampNodes) { + Node stampDup = duplicates.get(stampNode); + ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); + } + + // Replace all usages of the replacee with the value returned by the snippet + ValueNode returnValue = null; + if (returnNode != null) { + if (returnNode.result() instanceof LocalNode) { + returnValue = (ValueNode) replacements.get(returnNode.result()); + } else { + returnValue = (ValueNode) duplicates.get(returnNode.result()); + } + assert returnValue != null || replacee.usages().isEmpty(); + replacer.replace(replacee, returnValue); + + Node returnDuplicate = duplicates.get(returnNode); + if (returnDuplicate.isAlive()) { + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); + } + } + + // Remove the replacee from its graph + replacee.clearInputs(); + replacee.replaceAtUsages(null); + GraphUtil.killCFG(replacee); + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + return duplicates; + } + + /** + * Gets a copy of the specialized graph. + */ + public StructuredGraph copySpecializedGraph() { + return snippet.copy(); + } + + /** + * Replaces a given floating node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param replacer object that replaces the usages of {@code replacee} + * @param args the arguments to be bound to the flattened positional parameters of the snippet + */ + public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap replacements = bind(replaceeGraph, runtime, args); + Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); + + FixedWithNextNode lastFixedNode = tool.lastFixedNode(); + assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph; + FixedNode next = lastFixedNode.next(); + lastFixedNode.setNext(null); + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate); + + if (replacee instanceof StateSplit) { + for (StateSplit sideEffectNode : sideEffectNodes) { + assert ((StateSplit) replacee).hasSideEffect(); + Node sideEffectDup = duplicates.get(sideEffectNode); + ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); + } + } + for (ValueNode stampNode : stampNodes) { + Node stampDup = duplicates.get(stampNode); + ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); + } + + // Replace all usages of the replacee with the value returned by the snippet + assert returnNode != null : replaceeGraph; + ValueNode returnValue = null; + if (returnNode.result() instanceof LocalNode) { + returnValue = (ValueNode) replacements.get(returnNode.result()); + } else { + returnValue = (ValueNode) duplicates.get(returnNode.result()); + } + assert returnValue != null || replacee.usages().isEmpty(); + replacer.replace(replacee, returnValue); + + tool.setLastFixedNode(null); + Node returnDuplicate = duplicates.get(returnNode); + if (returnDuplicate.isAlive()) { + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); + if (next != null && next.predecessor() instanceof FixedWithNextNode) { + tool.setLastFixedNode((FixedWithNextNode) next.predecessor()); + } + } + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(snippet.toString()).append('('); + String sep = ""; + for (Map.Entry e : parameters.entrySet()) { + String name = e.getKey(); + Object value = e.getValue(); + buf.append(sep); + sep = ", "; + if (value == UNUSED_PARAMETER) { + buf.append(" ").append(name); + } else if (value instanceof LocalNode) { + LocalNode local = (LocalNode) value; + buf.append(local.kind().getJavaName()).append(' ').append(name); + } else { + LocalNode[] locals = (LocalNode[]) value; + String kind = locals.length == 0 ? "?" : locals[0].kind().getJavaName(); + buf.append(kind).append('[').append(locals.length).append("] ").append(name); + } + } + return buf.append(')').toString(); + } + + private static boolean checkTemplate(MetaAccessProvider runtime, SnippetTemplate.Key key, int parameterCount, ResolvedJavaMethod method, Signature signature) { + Set expected = new HashSet<>(); + for (int i = 0; i < parameterCount; i++) { + ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); + VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); + Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); + if (c != null) { + assert vp == null && p == null; + String name = c.value(); + expected.add(name); + Kind kind = signature.getParameterKind(i); + assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; + assert checkConstantArgument(runtime, method, signature, i, c.value(), key.get(name), kind); + } else if (vp != null) { + assert p == null; + String name = vp.value(); + expected.add(name); + assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; + assert key.get(name) instanceof Varargs; + Varargs varargs = (Varargs) key.get(name); + assert checkVarargs(method, signature, i, name, varargs); + } else { + assert p != null : method + ": parameter " + i + " must be annotated with exactly one of " + "@" + ConstantParameter.class.getSimpleName() + " or " + "@" + + VarargsParameter.class.getSimpleName() + " or " + "@" + Parameter.class.getSimpleName(); + } + } + if (!key.names().containsAll(expected)) { + expected.removeAll(key.names()); + assert false : expected + " missing from key " + key; + } + if (!expected.containsAll(key.names())) { + Set namesCopy = new HashSet<>(key.names()); + namesCopy.removeAll(expected); + assert false : "parameter(s) " + namesCopy + " should be annotated with @" + ConstantParameter.class.getSimpleName() + " or @" + VarargsParameter.class.getSimpleName() + " in " + + MetaUtil.format("%H.%n(%p)", method); + } + return true; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippets.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, 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; + +/** + * Marker interface for a class that defines one or more {@link Snippet}s. + */ +public interface Snippets { +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2011, 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.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Substitutions for {@link sun.misc.Unsafe} methods. + */ +@ClassSubstitution(sun.misc.Unsafe.class) +public class UnsafeSubstitutions { + + @MethodSubstitution(isStatic = false) + public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) { + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); + } + + @MethodSubstitution(isStatic = false) + public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) { + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); + } + + @MethodSubstitution(isStatic = false) + public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) { + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); + } + + @MethodSubstitution(isStatic = false) + public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + return UnsafeLoadNode.load(o, 0, offset, Kind.Object); + } + + @MethodSubstitution(isStatic = false) + public static Object getObjectVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + Object result = getObject(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Object); + } + + @MethodSubstitution(isStatic = false) + public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putObject(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putObject(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + Integer value = UnsafeLoadNode.load(o, 0, offset, Kind.Int); + return value; + } + + @MethodSubstitution(isStatic = false) + public static int getIntVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + int result = getInt(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putInt(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putInt(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Boolean result = UnsafeLoadNode.load(o, 0, offset, Kind.Boolean); + return result; + } + + @MethodSubstitution(isStatic = false) + public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + boolean result = getBoolean(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Boolean); + } + + @MethodSubstitution(isStatic = false) + public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putBoolean(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Byte result = UnsafeLoadNode.load(o, 0, offset, Kind.Byte); + return result; + } + + @MethodSubstitution(isStatic = false) + public static byte getByteVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + byte result = getByte(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putByte(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Short result = UnsafeLoadNode.load(o, 0, offset, Kind.Short); + return result; + } + + @MethodSubstitution(isStatic = false) + public static short getShortVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + short result = getShort(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putShort(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Character result = UnsafeLoadNode.load(o, 0, offset, Kind.Char); + return result; + } + + @MethodSubstitution(isStatic = false) + public static char getCharVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + char result = getChar(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putChar(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Long result = UnsafeLoadNode.load(o, 0, offset, Kind.Long); + return result; + } + + @MethodSubstitution(isStatic = false) + public static long getLongVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + long result = getLong(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putLong(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putLong(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Float result = UnsafeLoadNode.load(o, 0, offset, Kind.Float); + return result; + } + + @MethodSubstitution(isStatic = false) + public static float getFloatVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + float result = getFloat(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putFloat(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Double result = UnsafeLoadNode.load(o, 0, offset, Kind.Double); + return result; + } + + @MethodSubstitution(isStatic = false) + public static double getDoubleVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + double result = getDouble(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Double); + } + + @MethodSubstitution(isStatic = false) + public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putDouble(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) { + DirectStoreNode.store(address, value, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) { + DirectStoreNode.store(address, value, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) { + DirectStoreNode.store(address, value, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) { + DirectStoreNode.store(address, value, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) { + DirectStoreNode.store(address, value, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) { + DirectStoreNode.store(address, value, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) { + DirectStoreNode.store(address, value, Kind.Double); + } + + @MethodSubstitution(isStatic = false) + public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Double); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011, 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 static com.oracle.graal.nodes.calc.ConditionalNode.*; +import static com.oracle.graal.nodes.calc.Condition.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link UnsignedMath}. + */ +@ClassSubstitution(UnsignedMath.class) +public class UnsignedMathSubstitutions { + + @MethodSubstitution + public static boolean aboveThan(int a, int b) { + return materializeCondition(BT, b, a); + } + + @MethodSubstitution + public static boolean aboveOrEqual(int a, int b) { + return !materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + @MethodSubstitution + public static boolean belowThan(int a, int b) { + return materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + @MethodSubstitution + public static boolean belowOrEqual(int a, int b) { + return !materializeCondition(BT, b, a); + } + + /** + * Unsigned comparison aboveThan for two numbers. + */ + @MethodSubstitution + public static boolean aboveThan(long a, long b) { + return materializeCondition(BT, b, a); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + @MethodSubstitution + public static boolean aboveOrEqual(long a, long b) { + return !materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + @MethodSubstitution + public static boolean belowThan(long a, long b) { + return materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + @MethodSubstitution + public static boolean belowOrEqual(long a, long b) { + return !materializeCondition(BT, b, a); + } + + /** + * Unsigned division for two numbers. + */ + @MethodSubstitution + public static int divide(int a, int b) { + return unsignedDivide(Kind.Int, a, b); + } + + /** + * Unsigned remainder for two numbers. + */ + @MethodSubstitution + public static int remainder(int a, int b) { + return unsignedRemainder(Kind.Int, a, b); + } + + /** + * Unsigned division for two numbers. + */ + @MethodSubstitution + public static long divide(long a, long b) { + return unsignedDivide(Kind.Long, a, b); + } + + /** + * Unsigned remainder for two numbers. + */ + @MethodSubstitution + public static long remainder(long a, long b) { + return unsignedRemainder(Kind.Long, a, b); + } + + @NodeIntrinsic(UnsignedDivNode.class) + private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b); + + @NodeIntrinsic(UnsignedDivNode.class) + private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b); + + @NodeIntrinsic(UnsignedRemNode.class) + private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b); + + @NodeIntrinsic(UnsignedRemNode.class) + private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b); +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 2012, 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.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public BitCountNode(ValueNode value) { + super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (value.kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(Integer.bitCount((int) v), graph()); + } else if (value.kind() == Kind.Long) { + return ConstantNode.forInt(Long.bitCount(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int bitCount(int v); + + @NodeIntrinsic + public static native int bitCount(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitBitCount(result, gen.operand(value)); + gen.setResult(this, result); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2012, 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.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public BitScanForwardNode(ValueNode value) { + super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (value.kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(Integer.numberOfTrailingZeros((int) v), graph()); + } else if (value.kind() == Kind.Long) { + return ConstantNode.forInt(Long.numberOfTrailingZeros(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int scan(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitBitScanForward(result, gen.operand(value)); + gen.setResult(this, result); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 2012, 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.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public BitScanReverseNode(ValueNode value) { + super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (value.kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros((int) v), graph()); + } else if (value.kind() == Kind.Long) { + return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int scan(int v); + + @NodeIntrinsic + public static native int scan(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitBitScanReverse(result, gen.operand(value)); + gen.setResult(this, result); + } + +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 2013, 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.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +/** + * Instances of this node class will look for a preceding if node and put the given probability into + * the if node's taken probability. Then the branch probability node will be removed. This node is + * intended primarily for snippets, so that they can define their fast and slow paths. + */ +public class BranchProbabilityNode extends FixedWithNextNode implements Simplifiable { + + public static final double LIKELY_PROBABILITY = 0.6; + public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY; + + public static final double FREQUENT_PROBABILITY = 0.9; + public static final double NOT_FREQUENT_PROBABILITY = 1 - FREQUENT_PROBABILITY; + + public static final double FAST_PATH_PROBABILITY = 0.99; + public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY; + + public static final double NOT_DEOPT_PATH_PROBABILITY = 0.999; + public static final double DEOPT_PATH_PROBABILITY = 1 - NOT_DEOPT_PATH_PROBABILITY; + + private final double probability; + + public BranchProbabilityNode(double probability) { + super(StampFactory.forVoid()); + assert probability >= 0 && probability <= 1; + this.probability = probability; + } + + @Override + public void simplify(SimplifierTool tool) { + FixedNode current = this; + while (!(current instanceof BeginNode)) { + current = (FixedNode) current.predecessor(); + } + BeginNode begin = (BeginNode) current; + assert begin.predecessor() instanceof IfNode : "explicit branch probability cannot follow a merge, only if nodes"; + IfNode ifNode = (IfNode) begin.predecessor(); + if (ifNode.trueSuccessor() == begin) { + ifNode.setTrueSuccessorProbability(probability); + } else { + ifNode.setTrueSuccessorProbability(1 - probability); + } + + FixedNode next = next(); + setNext(null); + ((FixedWithNextNode) predecessor()).setNext(next); + GraphUtil.killCFG(this); + } + + @NodeIntrinsic + public static native void probability(@ConstantNodeParameter double probability); + +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 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.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +/** + * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a + * {@link StateSplit} and does not include a write barrier. + */ +public class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + @Input private ValueNode value; + @Input private ValueNode offset; + private final int displacement; + + public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) { + super(StampFactory.forVoid()); + this.object = object; + this.value = value; + this.offset = offset; + this.displacement = displacement; + } + + @NodeIntrinsic + public static native void storeObject(Object obj, @ConstantNodeParameter int displacement, long offset, Object value); + + @NodeIntrinsic + public static native void storeLong(Object obj, @ConstantNodeParameter int displacement, long offset, long value); + + @NodeIntrinsic + public static native void storeWord(Object obj, @ConstantNodeParameter int displacement, long offset, Word value); + + @NodeIntrinsic + public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value); + + @Override + public void lower(LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) this.graph(); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); + WriteNode write = graph.add(new WriteNode(object, value, location)); + graph.replaceFixedWithFixed(this, write); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, 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.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a + * {@link StateSplit} and takes a computed address instead of an object. + */ +public class DirectReadNode extends FixedWithNextNode implements LIRLowerable { + + @Input private ValueNode address; + private final Kind readKind; + + public DirectReadNode(ValueNode address, Kind readKind) { + super(StampFactory.forKind(readKind)); + this.address = address; + this.readKind = readKind; + } + + @Override + public void generate(LIRGeneratorTool gen) { + gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); + } + + @NodeIntrinsic + public static native T read(long address, @ConstantNodeParameter Kind kind); +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 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.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a + * {@link StateSplit} and takes a computed address instead of an object. + */ +public class DirectStoreNode extends FixedWithNextNode implements LIRLowerable { + + @Input private ValueNode address; + @Input private ValueNode value; + private final Kind kind; + + public DirectStoreNode(ValueNode address, ValueNode value, Kind kind) { + super(StampFactory.forVoid()); + this.address = address; + this.value = value; + this.kind = kind; + } + + @Override + public void generate(LIRGeneratorTool gen) { + Value v = gen.operand(value); + gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); + } + + /* + * The kind of the store is provided explicitly in these intrinsics because it is not always + * possible to determine the kind from the given value during compilation (because stack kinds + * are used). + */ + + @NodeIntrinsic + public static native void store(long address, boolean value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, byte value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, short value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, char value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, int value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, long value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, float value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, double value, @ConstantNodeParameter Kind kind); +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 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 java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Placeholder node to denote to snippet preparation that the following loop must be completely + * unrolled. + * + * @see VarargsParameter + */ +public final class ExplodeLoopNode extends FixedWithNextNode { + + public ExplodeLoopNode() { + super(StampFactory.forVoid()); + } + + public LoopBeginNode findLoopBegin() { + Node next = next(); + ArrayList succs = new ArrayList<>(); + while (!(next instanceof LoopBeginNode)) { + assert next != null : "cannot find loop after " + this; + for (Node n : next.cfgSuccessors()) { + succs.add(n); + } + if (succs.size() == 1) { + next = succs.get(0); + } else { + return null; + } + } + return (LoopBeginNode) next; + } + + /** + * A call to this method must be placed immediately prior to the loop that is to be exploded. + */ + @NodeIntrinsic + public static native void explodeLoop(); +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, 2011, 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.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Implements the semantics of {@link VarargsParameter}. + */ +public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable { + + @Input private ValueNode index; + + private final LocalNode[] locals; + + public LoadSnippetVarargParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) { + super(stamp); + this.index = index; + this.locals = locals; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (index.isConstant()) { + return locals[index.asConstant().asInt()]; + } + return this; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, 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 java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.*; + +public class MacroNode extends AbstractStateSplit implements Lowerable { + + @Input protected final NodeInputList arguments; + + private final int bci; + private final ResolvedJavaMethod targetMethod; + private final JavaType returnType; + + protected MacroNode(Invoke invoke) { + super(invoke.node().stamp(), invoke.stateAfter()); + this.arguments = new NodeInputList<>(this, invoke.methodCallTarget().arguments()); + this.bci = invoke.bci(); + this.targetMethod = invoke.methodCallTarget().targetMethod(); + this.returnType = invoke.methodCallTarget().returnType(); + } + + public int getBci() { + return bci; + } + + public ResolvedJavaMethod getTargetMethod() { + return targetMethod; + } + + @SuppressWarnings("unused") + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + return null; + } + + @Override + public void lower(LoweringTool tool) { + StructuredGraph snippetGraph = getSnippetGraph(tool); + + InvokeNode invoke = replaceWithInvoke(); + + if (snippetGraph != null) { + InliningUtil.inline(invoke, snippetGraph, false); + } + } + + private InvokeNode replaceWithInvoke() { + InvokeNode invoke = createInvoke(); + ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); + return invoke; + } + + protected InvokeNode createInvoke() { + InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special; + MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnType)); + InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); + invoke.setStateAfter(stateAfter()); + return invoke; + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2012, 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.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, LIRGenLowerable { + + @Input private ValueNode x; + private final Operation operation; + + public enum Operation { + ABS, SQRT, LOG, LOG10, SIN, COS, TAN + } + + public ValueNode x() { + return x; + } + + public Operation operation() { + return operation; + } + + public MathIntrinsicNode(ValueNode x, Operation op) { + super(StampFactory.forKind(x.kind())); + assert x.kind() == Kind.Double; + this.x = x; + this.operation = op; + } + + @Override + public void generate(LIRGenerator gen) { + Variable input = gen.load(gen.operand(x())); + Variable result = gen.newVariable(kind()); + switch (operation()) { + case ABS: + gen.emitMathAbs(result, input); + break; + case SQRT: + gen.emitMathSqrt(result, input); + break; + case LOG: + gen.emitMathLog(result, input, false); + break; + case LOG10: + gen.emitMathLog(result, input, true); + break; + case SIN: + gen.emitMathSin(result, input); + break; + case COS: + gen.emitMathCos(result, input); + break; + case TAN: + gen.emitMathTan(result, input); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + gen.setResult(this, result); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x().isConstant()) { + double value = x().asConstant().asDouble(); + switch (operation()) { + case ABS: + return ConstantNode.forDouble(Math.abs(value), graph()); + case SQRT: + return ConstantNode.forDouble(Math.sqrt(value), graph()); + case LOG: + return ConstantNode.forDouble(Math.log(value), graph()); + case LOG10: + return ConstantNode.forDouble(Math.log10(value), graph()); + case SIN: + return ConstantNode.forDouble(Math.sin(value), graph()); + case COS: + return ConstantNode.forDouble(Math.cos(value), graph()); + case TAN: + return ConstantNode.forDouble(Math.tan(value), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native double compute(double x, @ConstantNodeParameter Operation op); +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 2013, 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.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Access the value of a specific register. + */ +@NodeInfo(nameTemplate = "ReadRegister %{p#register}") +public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable { + + /** + * The fixed register to access. + */ + private final Register register; + + /** + * When true, subsequent uses of this node use the fixed register; when false, the value is + * moved into a new virtual register so that the fixed register is not seen by uses. + */ + private final boolean directUse; + + /** + * When true, this node is also an implicit definition of the value for the register allocator, + * i.e., the register is an implicit incoming value; when false, the register must be defined in + * the same method or must be an register excluded from register allocation. + */ + private final boolean incoming; + + public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) { + super(StampFactory.forKind(kind)); + this.register = register; + this.directUse = directUse; + this.incoming = incoming; + } + + /** + * Constructor to be used by node intrinsics where the stamp is inferred from the intrinsic + * definition. + */ + public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { + super(StampFactory.forNodeIntrinsic()); + this.register = register; + this.directUse = directUse; + this.incoming = incoming; + } + + @Override + public void generate(LIRGenerator generator) { + Value result = register.asValue(kind()); + if (incoming) { + generator.emitIncomingValues(new Value[]{result}); + } + if (!directUse) { + result = generator.emitMove(result); + } + generator.setResult(this, result); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "%" + register; + } else { + return super.toString(verbosity); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 2012, 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.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public ReverseBytesNode(ValueNode value) { + super(StampFactory.forKind(value.kind())); + assert kind().getStackKind() == Kind.Int || kind() == Kind.Long; + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(Integer.reverseBytes((int) v), graph()); + } else if (kind() == Kind.Long) { + return ConstantNode.forLong(Long.reverseBytes(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int reverse(int v); + + @NodeIntrinsic + public static native long reverse(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(value.kind()); + gen.emitByteSwap(result, gen.operand(value)); + gen.setResult(this, result); + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Wed Mar 20 22:30:33 2013 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, 2013, 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.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Changes the value of a specific register. + */ +@NodeInfo(nameTemplate = "WriteRegister %{p#register}") +public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable { + + /** + * The fixed register to access. + */ + private final Register register; + + /** + * The new value assigned to the register. + */ + @Input private ValueNode value; + + public WriteRegisterNode(Register register, ValueNode value) { + super(StampFactory.forVoid()); + this.register = register; + this.value = value; + } + + @Override + public void generate(LIRGeneratorTool generator) { + Value val = generator.operand(value); + generator.emitMove(val, register.asValue(val.getKind())); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "%" + register; + } else { + return super.toString(verbosity); + } + } +} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- a/graal/com.oracle.graal.snippets.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2013, 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.amd64; - -import static com.oracle.graal.replacements.SnippetTemplate.*; -import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; -import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.calc.ConvertNode.Op; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; - -/** - * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match - * the semantics of the JVM specification. - */ -public class AMD64ConvertSnippets implements Snippets { - - /** - * Converts a float to an int. - *

- * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the - * conversion. If the float value is a NaN, infinity or if the result of the conversion is - * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and - * extra tests are required on the float value to return the correct int value. - * - * @param input the float being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static int f2i(@Parameter("input") float input, @Parameter("result") int result) { - if (result == Integer.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Float.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0f) { - // input is > 0 -> return max int - return Integer.MAX_VALUE; - } - } - return result; - } - - /** - * Converts a float to a long. - *

- * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the - * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns - * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct - * long value. - * - * @param input the float being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static long f2l(@Parameter("input") float input, @Parameter("result") long result) { - if (result == Long.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Float.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0f) { - // input is > 0 -> return max int - return Long.MAX_VALUE; - } - } - return result; - } - - /** - * Converts a double to an int. - *

- * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the - * conversion. If the double value is a NaN, infinity or if the result of the conversion is - * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and - * extra tests are required on the double value to return the correct int value. - * - * @param input the double being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static int d2i(@Parameter("input") double input, @Parameter("result") int result) { - if (result == Integer.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Double.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0d) { - // input is positive -> return maxInt - return Integer.MAX_VALUE; - } - } - return result; - } - - /** - * Converts a double to a long. - *

- * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the - * conversion. If the double value is a NaN, infinity or if the result of the conversion is - * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra - * tests are required on the double value to return the correct long value. - * - * @param input the double being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static long d2l(@Parameter("input") double input, @Parameter("result") long result) { - if (result == Long.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Double.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0d) { - // input is positive -> return maxInt - return Long.MAX_VALUE; - } - } - return result; - } - - public static class Templates extends AbstractTemplates { - - private final ResolvedJavaMethod f2i; - private final ResolvedJavaMethod f2l; - private final ResolvedJavaMethod d2i; - private final ResolvedJavaMethod d2l; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, AMD64ConvertSnippets.class); - f2i = snippet("f2i", float.class, int.class); - f2l = snippet("f2l", float.class, long.class); - d2i = snippet("d2i", double.class, int.class); - d2l = snippet("d2l", double.class, long.class); - } - - public void lower(ConvertNode convert, LoweringTool tool) { - if (convert.opcode == Op.F2I) { - lower0(convert, tool, f2i); - } else if (convert.opcode == Op.F2L) { - lower0(convert, tool, f2l); - } else if (convert.opcode == Op.D2I) { - lower0(convert, tool, d2i); - } else if (convert.opcode == Op.D2L) { - lower0(convert, tool, d2l); - } - } - - private void lower0(ConvertNode convert, LoweringTool tool, ResolvedJavaMethod snippet) { - StructuredGraph graph = (StructuredGraph) convert.graph(); - - // Insert a unique placeholder node in place of the Convert node so that the - // Convert node can be used as an input to the snippet. All usage of the - // Convert node are replaced by the placeholder which in turn is replaced by the - // snippet. - - LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp())); - convert.replaceAtUsages(replacee); - Key key = new Key(snippet); - Arguments arguments = arguments("input", convert.value()).add("result", convert); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, arguments); - template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, arguments); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/overview.html --- a/graal/com.oracle.graal.snippets.test/overview.html Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ - - - - - - - - -Documentation for the com.oracle.graal.snippets.test project. - - - diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/CheckCastTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/CheckCastTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2011, 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.meta.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests the implementation of checkcast, allowing profiling information to be manually specified. - */ -public class CheckCastTest extends TypeCheckTest { - - @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { - CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); - if (ccn != null) { - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); - graph.replaceFixedWithFixed(ccn, ccnNew); - } - } - - @LongTest - public void test1() { - test("asNumber", profile(), 111); - test("asNumber", profile(Integer.class), 111); - test("asNumber", profile(Long.class, Short.class), 111); - test("asNumberExt", profile(), 111); - test("asNumberExt", profile(Integer.class), 111); - test("asNumberExt", profile(Long.class, Short.class), 111); - } - - @LongTest - public void test2() { - test("asString", profile(), "111"); - test("asString", profile(String.class), "111"); - test("asString", profile(String.class), "111"); - - final String nullString = null; - test("asString", profile(), nullString); - test("asString", profile(String.class), nullString); - test("asString", profile(String.class), nullString); - - test("asStringExt", profile(), "111"); - test("asStringExt", profile(String.class), "111"); - test("asStringExt", profile(String.class), "111"); - } - - @LongTest - public void test3() { - test("asNumber", profile(), "111"); - } - - @LongTest - public void test4() { - test("asString", profile(String.class), 111); - } - - @LongTest - public void test5() { - test("asNumberExt", profile(), "111"); - } - - @LongTest - public void test6() { - test("asStringExt", profile(String.class), 111); - } - - @LongTest - public void test7() { - Throwable throwable = new Exception(); - test("asThrowable", profile(), throwable); - test("asThrowable", profile(Throwable.class), throwable); - test("asThrowable", profile(Exception.class, Error.class), throwable); - } - - @LongTest - public void test8() { - test("arrayStore", new Object[100], "111"); - } - - @LongTest - public void test8_1() { - test("arrayFill", new Object[100], "111"); - } - - public static Number asNumber(Object o) { - return (Number) o; - } - - public static String asString(Object o) { - return (String) o; - } - - public static Throwable asThrowable(Object o) { - return (Throwable) o; - } - - public static ValueNode asValueNode(Object o) { - return (ValueNode) o; - } - - public static Number asNumberExt(Object o) { - Number n = (Number) o; - return n.intValue() + 10; - } - - public static String asStringExt(Object o) { - String s = (String) o; - return "#" + s; - } - - public static Object[] arrayStore(Object[] arr, Object value) { - arr[15] = value; - return arr; - } - - public static Object[] arrayFill(Object[] arr, Object value) { - for (int i = 0; i < arr.length; i++) { - arr[i] = value; - } - return arr; - } - - static class Depth1 implements Cloneable { - } - - static class Depth2 extends Depth1 { - } - - static class Depth3 extends Depth2 { - } - - static class Depth4 extends Depth3 { - } - - static class Depth5 extends Depth4 { - } - - static class Depth6 extends Depth5 { - } - - static class Depth7 extends Depth6 { - } - - static class Depth8 extends Depth7 { - } - - static class Depth9 extends Depth8 { - } - - static class Depth10 extends Depth9 { - } - - static class Depth11 extends Depth10 { - } - - static class Depth12 extends Depth11 { - } - - static class Depth13 extends Depth12 { - } - - static class Depth14 extends Depth12 { - } - - public static Depth12 asDepth12(Object o) { - return (Depth12) o; - } - - public static Depth12[][] asDepth12Arr(Object o) { - return (Depth12[][]) o; - } - - public static Cloneable asCloneable(Object o) { - return (Cloneable) o; - } - - @LongTest - public void test9() { - Object o = new Depth13(); - test("asDepth12", profile(), o); - test("asDepth12", profile(Depth13.class), o); - test("asDepth12", profile(Depth13.class, Depth14.class), o); - } - - @LongTest - public void test10() { - Object o = new Depth13[3][]; - test("asDepth12Arr", o); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2011, 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.test.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests for {@link InstanceOfDynamicNode}. - */ -public class InstanceOfDynamicTest extends GraalCompilerTest { - - public static int id(int value) { - return value; - } - - @LongTest - public void test100() { - final Object nul = null; - test("isStringDynamic", nul); - test("isStringDynamic", "object"); - test("isStringDynamic", Object.class); - } - - @LongTest - public void test101() { - final Object nul = null; - test("isStringIntDynamic", nul); - test("isStringIntDynamic", "object"); - test("isStringIntDynamic", Object.class); - } - - @LongTest - public void test103() { - test("isInstanceDynamic", String.class, null); - test("isInstanceDynamic", String.class, "object"); - test("isInstanceDynamic", String.class, Object.class); - test("isInstanceDynamic", int.class, null); - test("isInstanceDynamic", int.class, "Object"); - test("isInstanceDynamic", int.class, Object.class); - } - - @LongTest - public void test104() { - test("isInstanceIntDynamic", String.class, null); - test("isInstanceIntDynamic", String.class, "object"); - test("isInstanceIntDynamic", String.class, Object.class); - test("isInstanceIntDynamic", int.class, null); - test("isInstanceIntDynamic", int.class, "Object"); - test("isInstanceIntDynamic", int.class, Object.class); - } - - public static boolean isStringDynamic(Object o) { - return String.class.isInstance(o); - } - - public static int isStringIntDynamic(Object o) { - if (String.class.isInstance(o)) { - return o.toString().length(); - } - return o.getClass().getName().length(); - } - - public static boolean isInstanceDynamic(Class c, Object o) { - return c.isInstance(o); - } - - public static int isInstanceIntDynamic(Class c, Object o) { - if (c.isInstance(o)) { - return o.toString().length(); - } - return o.getClass().getName().length(); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/InstanceOfTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/InstanceOfTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,398 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.util.*; - - -import com.oracle.graal.api.code.CompilationResult.Call; -import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.CompilationResult.Site; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.CheckCastTest.*; - -/** - * Tests the implementation of instanceof, allowing profiling information to be manually specified. - */ -public class InstanceOfTest extends TypeCheckTest { - - @Override - protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { - phasePlan.disablePhase(InliningPhase.class); - } - - @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { - InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); - if (ion != null) { - InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile)); - graph.replaceFloating(ion, ionNew); - } - } - - @LongTest - public void test1() { - test("isString", profile(), "object"); - test("isString", profile(String.class), "object"); - - test("isString", profile(), Object.class); - test("isString", profile(String.class), Object.class); - } - - @LongTest - public void test2() { - test("isStringInt", profile(), "object"); - test("isStringInt", profile(String.class), "object"); - - test("isStringInt", profile(), Object.class); - test("isStringInt", profile(String.class), Object.class); - } - - @LongTest - public void test2_1() { - test("isStringIntComplex", profile(), "object"); - test("isStringIntComplex", profile(String.class), "object"); - - test("isStringIntComplex", profile(), Object.class); - test("isStringIntComplex", profile(String.class), Object.class); - } - - @LongTest - public void test3() { - Throwable throwable = new Exception(); - test("isThrowable", profile(), throwable); - test("isThrowable", profile(Throwable.class), throwable); - test("isThrowable", profile(Exception.class, Error.class), throwable); - - test("isThrowable", profile(), Object.class); - test("isThrowable", profile(Throwable.class), Object.class); - test("isThrowable", profile(Exception.class, Error.class), Object.class); - } - - @LongTest - public void test3_1() { - onlyFirstIsException(new Exception(), new Error()); - test("onlyFirstIsException", profile(), new Exception(), new Error()); - test("onlyFirstIsException", profile(), new Error(), new Exception()); - test("onlyFirstIsException", profile(), new Exception(), new Exception()); - test("onlyFirstIsException", profile(), new Error(), new Error()); - } - - @LongTest - public void test4() { - Throwable throwable = new Exception(); - test("isThrowableInt", profile(), throwable); - test("isThrowableInt", profile(Throwable.class), throwable); - test("isThrowableInt", profile(Exception.class, Error.class), throwable); - - test("isThrowableInt", profile(), Object.class); - test("isThrowableInt", profile(Throwable.class), Object.class); - test("isThrowableInt", profile(Exception.class, Error.class), Object.class); - } - - @LongTest - public void test5() { - Map map = new HashMap<>(); - test("isMap", profile(), map); - test("isMap", profile(HashMap.class), map); - test("isMap", profile(TreeMap.class, HashMap.class), map); - - test("isMap", profile(), Object.class); - test("isMap", profile(HashMap.class), Object.class); - test("isMap", profile(TreeMap.class, HashMap.class), Object.class); - } - - @LongTest - public void test6() { - Map map = new HashMap<>(); - test("isMapInt", profile(), map); - test("isMapInt", profile(HashMap.class), map); - test("isMapInt", profile(TreeMap.class, HashMap.class), map); - - test("isMapInt", profile(), Object.class); - test("isMapInt", profile(HashMap.class), Object.class); - test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); - } - - @LongTest - public void test7() { - Object o = new Depth13(); - test("isDepth12", profile(), o); - test("isDepth12", profile(Depth13.class), o); - test("isDepth12", profile(Depth13.class, Depth14.class), o); - - o = "not a depth"; - test("isDepth12", profile(), o); - test("isDepth12", profile(Depth13.class), o); - test("isDepth12", profile(Depth13.class, Depth14.class), o); - } - - @LongTest - public void test8() { - Object o = new Depth13(); - test("isDepth12Int", profile(), o); - test("isDepth12Int", profile(Depth13.class), o); - test("isDepth12Int", profile(Depth13.class, Depth14.class), o); - - o = "not a depth"; - test("isDepth12Int", profile(), o); - test("isDepth12Int", profile(Depth13.class), o); - test("isDepth12Int", profile(Depth13.class, Depth14.class), o); - } - - public static boolean isString(Object o) { - return o instanceof String; - } - - public static int isStringInt(Object o) { - if (o instanceof String) { - return id(1); - } - return id(0); - } - - public static int isStringIntComplex(Object o) { - if (o instanceof String || o instanceof Integer) { - return id(o instanceof String ? 1 : 0); - } - return id(0); - } - - public static int id(int value) { - return value; - } - - public static boolean isThrowable(Object o) { - return ((Throwable) o) instanceof Exception; - } - - public static int onlyFirstIsException(Throwable t1, Throwable t2) { - if (t1 instanceof Exception ^ t2 instanceof Exception) { - return t1 instanceof Exception ? 1 : -1; - } - return -1; - } - - public static int isThrowableInt(Object o) { - int result = o instanceof Throwable ? 4 : 5; - if (o instanceof Throwable) { - return id(4); - } - return result; - } - - public static boolean isMap(Object o) { - return o instanceof Map; - } - - public static int isMapInt(Object o) { - if (o instanceof Map) { - return id(1); - } - return id(0); - } - - public static boolean isDepth12(Object o) { - return o instanceof Depth12; - } - - public static int isDepth12Int(Object o) { - if (o instanceof Depth12) { - return id(0); - } - return id(0); - } - - abstract static class MySite { - - final int offset; - - MySite(int offset) { - this.offset = offset; - } - } - - static class MyMark extends MySite { - - MyMark(int offset) { - super(offset); - } - } - - abstract static class MySafepoint extends MySite { - - MySafepoint(int offset) { - super(offset); - } - } - - static class MyCall extends MySafepoint { - - MyCall(int offset) { - super(offset); - } - } - - @LongTest - public void test9() { - MyCall callAt63 = new MyCall(63); - MyMark markAt63 = new MyMark(63); - test("compareMySites", callAt63, callAt63); - test("compareMySites", callAt63, markAt63); - test("compareMySites", markAt63, callAt63); - test("compareMySites", markAt63, markAt63); - } - - public static int compareMySites(MySite s1, MySite s2) { - if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { - return s1 instanceof MyMark ? -1 : 1; - } - return s1.offset - s2.offset; - } - - @LongTest - public void test10() { - Mark[] noMarks = {}; - Call callAt63 = new Call(null, 63, 5, true, null); - Mark markAt63 = new Mark(63, "1", noMarks); - test("compareSites", callAt63, callAt63); - test("compareSites", callAt63, markAt63); - test("compareSites", markAt63, callAt63); - test("compareSites", markAt63, markAt63); - } - - public static int compareSites(Site s1, Site s2) { - if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { - return s1 instanceof Mark ? -1 : 1; - } - return s1.pcOffset - s2.pcOffset; - } - - /** - * This test exists to show the kind of pattern that is be optimizable by - * {@code removeIntermediateMaterialization()} in {@link IfNode}. - *

- * The test exists in this source file as the transformation was originally motivated by the - * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. - */ - @LongTest - public void test_removeIntermediateMaterialization() { - List list = Arrays.asList("1", "2", "3", "4"); - test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); - test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); - test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); - } - - public static String removeIntermediateMaterialization(List list, Object e, String a, String b) { - boolean test; - if (list == null || e == null) { - test = false; - } else { - test = false; - for (Object i : list) { - if (i.equals(e)) { - test = true; - break; - } - } - } - if (test) { - return a; - } - return b; - } - - abstract static class A { - } - - static class B extends A { - } - - static class C extends B { - } - - abstract static class D extends C { - } - - public static boolean isArrayOfA(Object o) { - return o instanceof A[]; - } - - public static boolean isArrayOfB(Object o) { - return o instanceof B[]; - } - - public static boolean isArrayOfC(Object o) { - return o instanceof C[]; - } - - public static boolean isArrayOfD(Object o) { - return o instanceof D[]; - } - - @LongTest - public void testArray() { - Object aArray = new A[10]; - test("isArrayOfA", aArray); - - Object bArray = new B[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - - Object cArray = new C[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfA", cArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - test("isArrayOfB", cArray); - test("isArrayOfC", aArray); - test("isArrayOfC", bArray); - test("isArrayOfC", cArray); - - Object dArray = new D[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfA", cArray); - test("isArrayOfA", dArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - test("isArrayOfB", cArray); - test("isArrayOfB", dArray); - test("isArrayOfC", aArray); - test("isArrayOfC", bArray); - test("isArrayOfC", cArray); - test("isArrayOfC", dArray); - test("isArrayOfD", aArray); - test("isArrayOfD", bArray); - test("isArrayOfD", cArray); - test("isArrayOfD", dArray); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/InvokeTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/InvokeTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2011, 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 org.junit.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; - -/** - * Tests the implementation of the snippets for lowering the INVOKE* instructions. - */ -public class InvokeTest extends GraalCompilerTest { - - @Override - protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { - phasePlan.disablePhase(InliningPhase.class); - } - - public interface I { - - String virtualMethod(String s); - } - - public static class A implements I { - - final String name = "A"; - - public String virtualMethod(String s) { - return name + s; - } - } - - @SuppressWarnings("static-method") - private String privateMethod(String s) { - return s; - } - - @Test - public void test1() { - test("invokestatic", "a string"); - test("invokespecialConstructor", "a string"); - test("invokespecial", this, "a string"); - test("invokevirtual", new A(), "a string"); - test("invokevirtual2", new A(), "a string"); - test("invokeinterface", new A(), "a string"); - Object[] args = {null}; - test("invokestatic", args); - test("invokespecialConstructor", args); - test("invokespecial", null, null); - test("invokevirtual", null, null); - test("invokevirtual2", null, null); - test("invokeinterface", null, null); - } - - public static String invokestatic(String s) { - return staticMethod(s); - } - - public static String staticMethod(String s) { - return s; - } - - public static String invokespecialConstructor(String s) { - return new A().virtualMethod(s); - } - - public static String invokespecial(InvokeTest a, String s) { - return a.privateMethod(s); - } - - public static String invokevirtual(A a, String s) { - return a.virtualMethod(s); - } - - public static String invokevirtual2(A a, String s) { - a.virtualMethod(s); - return a.virtualMethod(s); - } - - public static String invokeinterface(I i, String s) { - return i.virtualMethod(s); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,462 +0,0 @@ -/* - * Copyright (c) 2012, 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 static org.junit.Assert.*; - -import java.util.concurrent.*; - -import org.junit.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.ClassSubstitution.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Tests if {@link MethodSubstitution}s are inlined correctly. Most test cases only assert that - * there are no remaining invocations in the graph. This is sufficient if the method that is being - * substituted is a native method. For Java methods, additional checks are necessary. - */ -public class MethodSubstitutionTest extends GraalCompilerTest { - - @Test - public void testObjectSubstitutions() { - test("getClass_"); - test("objectHashCode"); - } - - @SuppressWarnings("all") - public static boolean getClass_(Object obj, Class clazz) { - return obj.getClass() == clazz; - } - - @SuppressWarnings("all") - public static int objectHashCode(TestClassA obj) { - return obj.hashCode(); - } - - @Test - public void testClassSubstitutions() { - test("getModifiers"); - test("isInstance"); - test("isInterface"); - test("isArray"); - test("isPrimitive"); - test("getSuperClass"); - test("getComponentType"); - } - - @SuppressWarnings("all") - public static int getModifiers(Class clazz) { - return clazz.getModifiers(); - } - - @SuppressWarnings("all") - public static boolean isInstance(Class clazz) { - return clazz.isInstance(Number.class); - } - - @SuppressWarnings("all") - public static boolean isInterface(Class clazz) { - return clazz.isInterface(); - } - - @SuppressWarnings("all") - public static boolean isArray(Class clazz) { - return clazz.isArray(); - } - - @SuppressWarnings("all") - public static boolean isPrimitive(Class clazz) { - return clazz.isPrimitive(); - } - - @SuppressWarnings("all") - public static Class getSuperClass(Class clazz) { - return clazz.getSuperclass(); - } - - @SuppressWarnings("all") - public static Class getComponentType(Class clazz) { - return clazz.getComponentType(); - } - - @Test - public void testThreadSubstitutions() { - test("currentThread"); - test("threadIsInterrupted"); - test("threadInterrupted"); - } - - @SuppressWarnings("all") - public static Thread currentThread() { - return Thread.currentThread(); - } - - @SuppressWarnings("all") - public static boolean threadIsInterrupted(Thread thread) { - return thread.isInterrupted(); - } - - @SuppressWarnings("all") - public static boolean threadInterrupted() { - return Thread.interrupted(); - } - - @Test - public void testSystemSubstitutions() { - test("systemTime"); - test("systemIdentityHashCode"); - } - - @SuppressWarnings("all") - public static long systemTime() { - return System.currentTimeMillis() + System.nanoTime(); - } - - @SuppressWarnings("all") - public static int systemIdentityHashCode(Object obj) { - return System.identityHashCode(obj); - } - - @Test - public void testUnsafeSubstitutions() { - test("unsafeCompareAndSwapInt"); - test("unsafeCompareAndSwapLong"); - test("unsafeCompareAndSwapObject"); - - test("unsafeGetBoolean"); - test("unsafeGetByte"); - test("unsafeGetShort"); - test("unsafeGetChar"); - test("unsafeGetInt"); - test("unsafeGetFloat"); - test("unsafeGetDouble"); - test("unsafeGetObject"); - - test("unsafePutBoolean"); - test("unsafePutByte"); - test("unsafePutShort"); - test("unsafePutChar"); - test("unsafePutInt"); - test("unsafePutFloat"); - test("unsafePutDouble"); - test("unsafePutObject"); - - test("unsafeDirectMemoryRead"); - test("unsafeDirectMemoryWrite"); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapInt(obj, offset, 0, 1); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapLong(obj, offset, 0, 1); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapObject(obj, offset, null, new Object()); - } - - @SuppressWarnings("all") - public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) { - return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) { - return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) { - return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) { - return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) { - return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) { - return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) { - return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) { - return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) { - return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) { - unsafe.putBoolean(obj, offset, value); - unsafe.putBooleanVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) { - unsafe.putByte(obj, offset, value); - unsafe.putByteVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) { - unsafe.putShort(obj, offset, value); - unsafe.putShortVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) { - unsafe.putChar(obj, offset, value); - unsafe.putCharVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) { - unsafe.putInt(obj, offset, value); - unsafe.putIntVolatile(obj, offset, value); - unsafe.putOrderedInt(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) { - unsafe.putLong(obj, offset, value); - unsafe.putLongVolatile(obj, offset, value); - unsafe.putOrderedLong(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) { - unsafe.putFloat(obj, offset, value); - unsafe.putFloatVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) { - unsafe.putDouble(obj, offset, value); - unsafe.putDoubleVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) { - unsafe.putObject(obj, offset, value); - unsafe.putObjectVolatile(obj, offset, value); - unsafe.putOrderedObject(obj, offset, value); - } - - @SuppressWarnings("all") - public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) { - // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist - return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address); - } - - @SuppressWarnings("all") - public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) { - // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist - unsafe.putByte(address, value); - unsafe.putShort(address, value); - unsafe.putChar(address, (char) value); - unsafe.putInt(address, value); - unsafe.putLong(address, value); - unsafe.putFloat(address, value); - unsafe.putDouble(address, value); - } - - @Test - public void testMathSubstitutions() { - assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), MathIntrinsicNode.class); // Java - test("math"); - } - - @SuppressWarnings("all") - public static double mathAbs(double value) { - return Math.abs(value); - } - - @SuppressWarnings("all") - public static double math(double value) { - return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); - // Math.exp(value) + - // Math.pow(value, 13); - } - - @Test - public void testIntegerSubstitutions() { - assertInGraph(test("integerReverseBytes"), ReverseBytesNode.class); // Java - assertInGraph(test("integerNumberOfLeadingZeros"), BitScanReverseNode.class); // Java - assertInGraph(test("integerNumberOfTrailingZeros"), BitScanForwardNode.class); // Java - assertInGraph(test("integerBitCount"), BitCountNode.class); // Java - } - - @SuppressWarnings("all") - public static int integerReverseBytes(int value) { - return Integer.reverseBytes(value); - } - - @SuppressWarnings("all") - public static int integerNumberOfLeadingZeros(int value) { - return Integer.numberOfLeadingZeros(value); - } - - @SuppressWarnings("all") - public static int integerNumberOfTrailingZeros(int value) { - return Integer.numberOfTrailingZeros(value); - } - - @SuppressWarnings("all") - public static int integerBitCount(int value) { - return Integer.bitCount(value); - } - - @Test - public void testLongSubstitutions() { - assertInGraph(test("longReverseBytes"), ReverseBytesNode.class); // Java - assertInGraph(test("longNumberOfLeadingZeros"), BitScanReverseNode.class); // Java - assertInGraph(test("longNumberOfTrailingZeros"), BitScanForwardNode.class); // Java - assertInGraph(test("longBitCount"), BitCountNode.class); // Java - } - - @SuppressWarnings("all") - public static long longReverseBytes(long value) { - return Long.reverseBytes(value); - } - - @SuppressWarnings("all") - public static long longNumberOfLeadingZeros(long value) { - return Long.numberOfLeadingZeros(value); - } - - @SuppressWarnings("all") - public static long longNumberOfTrailingZeros(long value) { - return Long.numberOfTrailingZeros(value); - } - - @SuppressWarnings("all") - public static int longBitCount(long value) { - return Long.bitCount(value); - } - - @Test - public void testFloatSubstitutions() { - assertInGraph(test("floatToIntBits"), ConvertNode.class); // Java - test("intBitsToFloat"); - } - - @SuppressWarnings("all") - public static int floatToIntBits(float value) { - return Float.floatToIntBits(value); - } - - @SuppressWarnings("all") - public static float intBitsToFloat(int value) { - return Float.intBitsToFloat(value); - } - - @Test - public void testDoubleSubstitutions() { - assertInGraph(test("doubleToLongBits"), ConvertNode.class); // Java - test("longBitsToDouble"); - } - - @SuppressWarnings("all") - public static long doubleToLongBits(double value) { - return Double.doubleToLongBits(value); - } - - @SuppressWarnings("all") - public static double longBitsToDouble(long value) { - return Double.longBitsToDouble(value); - } - - private StructuredGraph test(final String snippet) { - return Debug.scope("MethodSubstitutionTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable() { - - @Override - public StructuredGraph call() { - StructuredGraph graph = parse(snippet); - PhasePlan phasePlan = getDefaultPhasePlan(); - Assumptions assumptions = new Assumptions(true); - new ComputeProbabilityPhase().apply(graph); - Debug.dump(graph, "Graph"); - new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - Debug.dump(graph, "Graph"); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - - assertNotInGraph(graph, Invoke.class); - return graph; - } - }); - } - - private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { - for (Node node : graph.getNodes()) { - if (clazz.isInstance(node)) { - fail(node.toString()); - } - } - return graph; - } - - private static StructuredGraph assertInGraph(StructuredGraph graph, Class clazz) { - for (Node node : graph.getNodes()) { - if (clazz.isInstance(node)) { - return graph; - } - } - fail("Graph does not contain a node of class " + clazz.getName()); - return graph; - } - - private static class TestClassA { - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/MonitorTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/MonitorTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2012, 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 org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.virtual.phases.ea.*; - -public class MonitorTest extends GraalCompilerTest { - - @Test - public void test0() { - test("lockObjectSimple", new Object(), new Object()); - test("lockObjectSimple", new Object(), null); - } - - @Test - public void test0_1() { - test("lockThisSimple", "test1", new Object()); - test("lockThisSimple", "test1", null); - } - - @Test - public void test0_2() { - test("lockObjectSimple", null, "test1"); - } - - @Test - public void test1_1() { - test("lockObject", new Object(), "test1", new String[1]); - } - - @Test - public void test1_2() { - test("lockObject", null, "test1_1", new String[1]); - } - - @Test - public void test2() { - test("lockThis", "test2", new String[1]); - } - - /** - * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}. - */ - @Test - public void test3() { - test("lockLocalObject", "test3", new String[1]); - } - - /** - * Tests recursive locking of objects which should be biasable. - */ - @Test - public void test4() { - Chars src = new Chars("1234567890".toCharArray()); - Chars dst = new Chars(src.data.length); - test("copyObj", src, dst, 100); - } - - /** - * Tests recursive locking of objects which do not appear to be biasable. - */ - @Test - public void test5() { - char[] src = "1234567890".toCharArray(); - char[] dst = new char[src.length]; - test("copyArr", src, dst, 100); - } - - /** - * Extends {@link #test4()} with contention. - */ - @Test - public void test6() { - Chars src = new Chars("1234567890".toCharArray()); - Chars dst = new Chars(src.data.length); - int n = Runtime.getRuntime().availableProcessors(); - testN(n, "copyObj", src, dst, 100); - } - - /** - * Extends {@link #test5()} with contention. - */ - @Test - public void test7() { - char[] src = "1234567890".toCharArray(); - char[] dst = new char[src.length]; - int n = Runtime.getRuntime().availableProcessors(); - testN(n, "copyArr", src, dst, 100); - } - - private static String setAndGet(String[] box, String value) { - synchronized (box) { - box[0] = null; - } - - // Do a GC while a object is locked (by the caller) - System.gc(); - - synchronized (box) { - box[0] = value; - } - return box[0]; - } - - public static Object lockObjectSimple(Object o, Object value) { - synchronized (o) { - value.hashCode(); - return value; - } - } - - public String lockThisSimple(String value, Object o) { - synchronized (this) { - synchronized (value) { - o.hashCode(); - return value; - } - } - } - - public static String lockObject(Object o, String value, String[] box) { - synchronized (o) { - return setAndGet(box, value); - } - } - - public String lockThis(String value, String[] box) { - synchronized (this) { - return setAndGet(box, value); - } - } - - public static String lockLocalObject(String value, String[] box) { - Object o = new Object(); - synchronized (o) { - return setAndGet(box, value); - } - } - - static class Chars { - - final char[] data; - - public Chars(int size) { - this.data = new char[size]; - } - - public Chars(char[] data) { - this.data = data; - } - } - - public static String copyObj(Chars src, Chars dst, int n) { - System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.data.length); - int total = 0; - for (int j = 0; j < n; j++) { - for (int i = 0; i < src.data.length; i++) { - synchronized (src) { - synchronized (dst) { - synchronized (src) { - synchronized (dst) { - dst.data[i] = src.data[i]; - total++; - } - } - } - } - } - } - System.out.println(Thread.currentThread().getName() + " total " + total); - return new String(dst.data); - } - - public static String copyArr(char[] src, char[] dst, int n) { - System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.length); - int total = 0; - for (int j = 0; j < n; j++) { - for (int i = 0; i < src.length; i++) { - synchronized (src) { - synchronized (dst) { - synchronized (src) { - synchronized (dst) { - dst[i] = src[i]; - total++; - } - } - } - } - } - } - System.out.println(Thread.currentThread().getName() + " total " + total); - return new String(dst); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/NewArrayTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/NewArrayTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2011, 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 org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; - -/** - * Tests the implementation of {@code [A]NEWARRAY}. - */ -public class NewArrayTest extends GraalCompilerTest { - - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - if (expected instanceof int[]) { - Assert.assertArrayEquals((int[]) expected, (int[]) actual); - } else if (expected instanceof byte[]) { - Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); - } else if (expected instanceof char[]) { - Assert.assertArrayEquals((char[]) expected, (char[]) actual); - } else if (expected instanceof short[]) { - Assert.assertArrayEquals((short[]) expected, (short[]) actual); - } else if (expected instanceof float[]) { - Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); - } else if (expected instanceof long[]) { - Assert.assertArrayEquals((long[]) expected, (long[]) actual); - } else if (expected instanceof double[]) { - Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); - } else if (expected instanceof Object[]) { - Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); - } else { - Assert.fail("non-array value encountered: " + expected); - } - } - - @LongTest - public void test1() { - for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { - test("new" + type + "Array7"); - test("new" + type + "ArrayMinus7"); - test("new" + type + "Array", 7); - test("new" + type + "Array", -7); - test("new" + type + "Array", Integer.MAX_VALUE); - test("new" + type + "Array", Integer.MIN_VALUE); - } - } - - public static Object newCharArray7() { - return new char[7]; - } - - public static Object newCharArrayMinus7() { - return new char[-7]; - } - - public static Object newCharArray(int length) { - return new char[length]; - } - - public static Object newShortArray7() { - return new short[7]; - } - - public static Object newShortArrayMinus7() { - return new short[-7]; - } - - public static Object newShortArray(int length) { - return new short[length]; - } - - public static Object newFloatArray7() { - return new float[7]; - } - - public static Object newFloatArrayMinus7() { - return new float[-7]; - } - - public static Object newFloatArray(int length) { - return new float[length]; - } - - public static Object newLongArray7() { - return new long[7]; - } - - public static Object newLongArrayMinus7() { - return new long[-7]; - } - - public static Object newLongArray(int length) { - return new long[length]; - } - - public static Object newDoubleArray7() { - return new double[7]; - } - - public static Object newDoubleArrayMinus7() { - return new double[-7]; - } - - public static Object newDoubleArray(int length) { - return new double[length]; - } - - public static Object newIntArray7() { - return new int[7]; - } - - public static Object newIntArrayMinus7() { - return new int[-7]; - } - - public static Object newIntArray(int length) { - return new int[length]; - } - - public static Object newByteArray7() { - return new byte[7]; - } - - public static Object newByteArrayMinus7() { - return new byte[-7]; - } - - public static Object newByteArray(int length) { - return new byte[length]; - } - - public static Object newStringArray7() { - return new String[7]; - } - - public static Object newStringArrayMinus7() { - return new String[-7]; - } - - public static Object newStringArray(int length) { - return new String[length]; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/NewInstanceTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/NewInstanceTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.util.*; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; - -/** - * Tests the implementation of {@code NEW}. - */ -public class NewInstanceTest extends GraalCompilerTest { - - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - - if (expected instanceof Object[]) { - Assert.assertTrue(actual instanceof Object[]); - Object[] eArr = (Object[]) expected; - Object[] aArr = (Object[]) actual; - Assert.assertTrue(eArr.length == aArr.length); - for (int i = 0; i < eArr.length; i++) { - assertEquals(eArr[i], aArr[i]); - } - } else if (expected.getClass() != Object.class) { - try { - expected.getClass().getDeclaredMethod("equals", Object.class); - super.assertEquals(expected, actual); - } catch (Exception e) { - } - } - } - - @LongTest - public void test1() { - test("newObject"); - } - - @LongTest - public void test2() { - test("newObjectTwice"); - } - - public static Object newObject() { - return new Object(); - } - - @LongTest - public void test3() { - test("newObjectLoop", 100); - } - - @LongTest - public void test4() { - test("newBigObject"); - } - - @LongTest - public void test5() { - test("newSomeObject"); - } - - @LongTest - public void test6() { - test("newEmptyString"); - } - - @LongTest - public void test7() { - test("newString", "value"); - } - - @LongTest - public void test8() { - test("newHashMap", 31); - } - - @LongTest - public void test9() { - test("newRegression", true); - } - - public static Object[] newObjectTwice() { - Object[] res = {new Object(), new Object()}; - return res; - } - - public static Object[] newObjectLoop(int n) { - Object[] res = new Object[n]; - for (int i = 0; i < n; i++) { - res[i] = new Object(); - } - return res; - } - - public static BigObject newBigObject() { - return new BigObject(); - } - - public static SomeObject newSomeObject() { - return new SomeObject(); - } - - public static String newEmptyString() { - return new String(); - } - - public static String newString(String value) { - return new String(value); - } - - public static HashMap newHashMap(int initialCapacity) { - return new HashMap(initialCapacity); - } - - static class SomeObject { - - String name = "o1"; - HashMap map = new HashMap<>(); - - public SomeObject() { - map.put(name, this.getClass()); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof SomeObject) { - SomeObject so = (SomeObject) obj; - return so.name.equals(name) && so.map.equals(map); - } - return false; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - } - - static class BigObject { - - Object f01; - Object f02; - Object f03; - Object f04; - Object f05; - Object f06; - Object f07; - Object f08; - Object f09; - Object f10; - Object f12; - Object f13; - Object f14; - Object f15; - Object f16; - Object f17; - Object f18; - Object f19; - Object f20; - Object f21; - Object f22; - Object f23; - Object f24; - Object f25; - Object f26; - Object f27; - Object f28; - Object f29; - Object f30; - Object f31; - Object f32; - Object f33; - Object f34; - Object f35; - Object f36; - Object f37; - Object f38; - Object f39; - Object f40; - Object f41; - Object f42; - Object f43; - Object f44; - Object f45; - } - - /** - * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top' - * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the - * allocated B object in the true branch overwrote the allocated array. The cause is that - * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also - * floating. The fix was to make RegisterNode a fixed node (which it should have been in the - * first place). - */ - public static Object newRegression(boolean condition) { - Object result; - if (condition) { - Object[] arr = {0, 1, 2, 3, 4, 5}; - result = new B(); - for (int i = 0; i < arr.length; ++i) { - // If the bug exists, the values of arr will now be deadbeef values - // and the virtual dispatch will cause a segfault. This can result in - // either a VM crash or a spurious NullPointerException. - if (arr[i].equals(Integer.valueOf(i))) { - return false; - } - } - } else { - result = new B(); - } - return result; - } - - static class B { - - long f1 = 0xdeadbeefdeadbe01L; - long f2 = 0xdeadbeefdeadbe02L; - long f3 = 0xdeadbeefdeadbe03L; - long f4 = 0xdeadbeefdeadbe04L; - long f5 = 0xdeadbeefdeadbe05L; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2012, 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 java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests the lowering of the MULTIANEWARRAY instruction. - */ -public class NewMultiArrayTest extends GraalCompilerTest { - - private static int rank(ResolvedJavaType type) { - String name = type.getName(); - int dims = 0; - while (dims < name.length() && name.charAt(dims) == '[') { - dims++; - } - return dims; - } - - @Override - protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { - boolean forceCompile = false; - if (bottomType != null) { - List snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot(); - assert snapshot != null; - assert snapshot.size() == 1; - - NewMultiArrayNode node = snapshot.get(0); - assert rank(arrayType) == dimensions.length; - int rank = dimensions.length; - ValueNode[] dimensionNodes = new ValueNode[rank]; - for (int i = 0; i < rank; i++) { - dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph)); - } - - NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes)); - graph.replaceFixedWithFixed(node, repl); - forceCompile = true; - } - return super.getCode(method, graph, forceCompile); - } - - @Override - protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - if (bottomType != null) { - try { - return Array.newInstance(bottomClass, dimensions); - } catch (Exception e) { - throw new InvocationTargetException(e); - } - } - return super.referenceInvoke(method, receiver, args); - } - - ResolvedJavaType arrayType; - ResolvedJavaType bottomType; - Class bottomClass; - int[] dimensions; - - @LongTest - public void test1() { - for (Class clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { - bottomClass = clazz; - bottomType = runtime.lookupJavaType(clazz); - arrayType = bottomType; - for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) { - while (rank(arrayType) != rank) { - arrayType = arrayType.getArrayClass(); - } - - dimensions = new int[rank]; - for (int i = 0; i < rank; i++) { - dimensions[i] = 1; - } - - test("newMultiArray"); - } - } - bottomType = null; - arrayType = null; - } - - public static Object newMultiArray() { - // This is merely a template - the NewMultiArrayNode is replaced in getCode() above. - // This also means we need a separate test for correct handling of negative dimensions - // as deoptimization won't do what we want for a graph modified to be different from the - // source bytecode. - return new Object[10][9][8]; - } - - @LongTest - public void test2() { - test("newMultiArrayException"); - } - - public static Object newMultiArrayException() { - return new Object[10][9][-8]; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/PointerTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/PointerTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,399 +0,0 @@ -/* - * Copyright (c) 2013, 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 java.lang.reflect.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.word.*; - -/** - * Tests for the {@link Pointer} read and write operations. - */ -public class PointerTest extends GraalCompilerTest implements Snippets { - - private static final Object ID = new Object(); - private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; - private final TargetDescription target; - private final ReplacementsInstaller installer; - - public PointerTest() { - target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); - installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); - } - - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - - @Override - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); - } - - @Test - public void test_read1() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "1"), kind, false, ID); - } - } - - @Test - public void test_read2() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "2"), kind, true, ID); - } - } - - @Test - public void test_read3() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION); - } - } - - @Test - public void test_write1() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); - } - } - - @Test - public void test_write2() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); - } - } - - @Test - public void test_write3() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); - } - } - - private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { - ReadNode read = (ReadNode) graph.start().next(); - Assert.assertEquals(kind.getStackKind(), read.kind()); - - UnsafeCastNode cast = (UnsafeCastNode) read.object(); - Assert.assertEquals(graph.getLocal(0), cast.object()); - Assert.assertEquals(target.wordKind, cast.kind()); - - IndexedLocationNode location = (IndexedLocationNode) read.location(); - Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); - - if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); - Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); - Assert.assertEquals(graph.getLocal(1), convert.value()); - } else { - Assert.assertEquals(graph.getLocal(1), location.index()); - } - - ReturnNode ret = (ReturnNode) read.next(); - Assert.assertEquals(read, ret.result()); - } - - private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { - WriteNode write = (WriteNode) graph.start().next(); - Assert.assertEquals(graph.getLocal(2), write.value()); - Assert.assertEquals(Kind.Void, write.kind()); - Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); - - UnsafeCastNode cast = (UnsafeCastNode) write.object(); - Assert.assertEquals(graph.getLocal(0), cast.object()); - Assert.assertEquals(target.wordKind, cast.kind()); - - IndexedLocationNode location = (IndexedLocationNode) write.location(); - Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); - - if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); - Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); - Assert.assertEquals(graph.getLocal(1), convert.value()); - } else { - Assert.assertEquals(graph.getLocal(1), location.index()); - } - - AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); - Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); - - ReturnNode ret = (ReturnNode) stateSplit.next(); - Assert.assertEquals(null, ret.result()); - } - - @Snippet - public static byte readByte1(Object o, int offset) { - return Word.fromObject(o).readByte(offset, ID); - } - - @Snippet - public static byte readByte2(Object o, int offset) { - return Word.fromObject(o).readByte(Word.signed(offset), ID); - } - - @Snippet - public static byte readByte3(Object o, int offset) { - return Word.fromObject(o).readByte(offset); - } - - @Snippet - public static void writeByte1(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(offset, value, ID); - } - - @Snippet - public static void writeByte2(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeByte3(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(offset, value); - } - - @Snippet - public static char readChar1(Object o, int offset) { - return Word.fromObject(o).readChar(offset, ID); - } - - @Snippet - public static char readChar2(Object o, int offset) { - return Word.fromObject(o).readChar(Word.signed(offset), ID); - } - - @Snippet - public static char readChar3(Object o, int offset) { - return Word.fromObject(o).readChar(offset); - } - - @Snippet - public static void writeChar1(Object o, int offset, char value) { - Word.fromObject(o).writeChar(offset, value, ID); - } - - @Snippet - public static void writeChar2(Object o, int offset, char value) { - Word.fromObject(o).writeChar(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeChar3(Object o, int offset, char value) { - Word.fromObject(o).writeChar(offset, value); - } - - @Snippet - public static short readShort1(Object o, int offset) { - return Word.fromObject(o).readShort(offset, ID); - } - - @Snippet - public static short readShort2(Object o, int offset) { - return Word.fromObject(o).readShort(Word.signed(offset), ID); - } - - @Snippet - public static short readShort3(Object o, int offset) { - return Word.fromObject(o).readShort(offset); - } - - @Snippet - public static void writeShort1(Object o, int offset, short value) { - Word.fromObject(o).writeShort(offset, value, ID); - } - - @Snippet - public static void writeShort2(Object o, int offset, short value) { - Word.fromObject(o).writeShort(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeShort3(Object o, int offset, short value) { - Word.fromObject(o).writeShort(offset, value); - } - - @Snippet - public static int readInt1(Object o, int offset) { - return Word.fromObject(o).readInt(offset, ID); - } - - @Snippet - public static int readInt2(Object o, int offset) { - return Word.fromObject(o).readInt(Word.signed(offset), ID); - } - - @Snippet - public static int readInt3(Object o, int offset) { - return Word.fromObject(o).readInt(offset); - } - - @Snippet - public static void writeInt1(Object o, int offset, int value) { - Word.fromObject(o).writeInt(offset, value, ID); - } - - @Snippet - public static void writeInt2(Object o, int offset, int value) { - Word.fromObject(o).writeInt(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeInt3(Object o, int offset, int value) { - Word.fromObject(o).writeInt(offset, value); - } - - @Snippet - public static long readLong1(Object o, int offset) { - return Word.fromObject(o).readLong(offset, ID); - } - - @Snippet - public static long readLong2(Object o, int offset) { - return Word.fromObject(o).readLong(Word.signed(offset), ID); - } - - @Snippet - public static long readLong3(Object o, int offset) { - return Word.fromObject(o).readLong(offset); - } - - @Snippet - public static void writeLong1(Object o, int offset, long value) { - Word.fromObject(o).writeLong(offset, value, ID); - } - - @Snippet - public static void writeLong2(Object o, int offset, long value) { - Word.fromObject(o).writeLong(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeLong3(Object o, int offset, long value) { - Word.fromObject(o).writeLong(offset, value); - } - - @Snippet - public static float readFloat1(Object o, int offset) { - return Word.fromObject(o).readFloat(offset, ID); - } - - @Snippet - public static float readFloat2(Object o, int offset) { - return Word.fromObject(o).readFloat(Word.signed(offset), ID); - } - - @Snippet - public static float readFloat3(Object o, int offset) { - return Word.fromObject(o).readFloat(offset); - } - - @Snippet - public static void writeFloat1(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(offset, value, ID); - } - - @Snippet - public static void writeFloat2(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeFloat3(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(offset, value); - } - - @Snippet - public static double readDouble1(Object o, int offset) { - return Word.fromObject(o).readDouble(offset, ID); - } - - @Snippet - public static double readDouble2(Object o, int offset) { - return Word.fromObject(o).readDouble(Word.signed(offset), ID); - } - - @Snippet - public static double readDouble3(Object o, int offset) { - return Word.fromObject(o).readDouble(offset); - } - - @Snippet - public static void writeDouble1(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(offset, value, ID); - } - - @Snippet - public static void writeDouble2(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeDouble3(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(offset, value); - } - - @Snippet - public static Object readObject1(Object o, int offset) { - return Word.fromObject(o).readObject(offset, ID); - } - - @Snippet - public static Object readObject2(Object o, int offset) { - return Word.fromObject(o).readObject(Word.signed(offset), ID); - } - - @Snippet - public static Object readObject3(Object o, int offset) { - return Word.fromObject(o).readObject(offset); - } - - @Snippet - public static void writeObject1(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(offset, value, ID); - } - - @Snippet - public static void writeObject2(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeObject3(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(offset, value); - } - -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/TypeCheckTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/TypeCheckTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011, 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.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; - -/** - * Base class for checkcast and instanceof test classes. - */ -public abstract class TypeCheckTest extends GraalCompilerTest { - - protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); - - protected JavaTypeProfile currentProfile; - - @Override - protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { - boolean forceCompile = false; - if (currentProfile != null) { - replaceProfile(graph, currentProfile); - forceCompile = true; - } - return super.getCode(method, graph, forceCompile); - } - - protected JavaTypeProfile profile(Class... types) { - if (types.length == 0) { - return null; - } - ProfiledType[] ptypes = new ProfiledType[types.length]; - for (int i = 0; i < types.length; i++) { - ptypes[i] = new ProfiledType(runtime.lookupJavaType(types[i]), 1.0D / types.length); - } - return new JavaTypeProfile(0.0D, ptypes); - } - - protected void test(String name, JavaTypeProfile profile, Object... args) { - assert currentProfile == null; - currentProfile = profile; - try { - super.test(name, args); - } finally { - currentProfile = null; - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/WordTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/replacements/WordTest.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.word.*; - -/** - * Tests for the {@link Word} type. - */ -public class WordTest extends GraalCompilerTest implements Snippets { - - private final ReplacementsInstaller installer; - - public WordTest() { - TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); - installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); - } - - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - - @Override - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); - } - - @LongTest - public void construction() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, - Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; - for (long word : words) { - test("unsigned_long", word); - test("unsigned_int", (int) word); - test("signed_long", word); - test("signed_int", (int) word); - } - } - - @LongTest - public void test_arithmetic() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, - Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; - for (long word : words) { - test("unsigned_not", word); - test("signed_not", word); - for (long addend : words) { - test("unsigned_plus_int", word, (int) addend); - test("unsigned_minus_int", word, (int) addend); - test("unsigned_plus_int", word, -((int) addend)); - test("unsigned_minus_int", word, -((int) addend)); - test("unsigned_plus_long", word, addend); - test("unsigned_minus_long", word, addend); - test("unsigned_plus_long", word, -addend); - test("unsigned_minus_long", word, -addend); - test("signed_plus_int", word, (int) addend); - test("signed_minus_int", word, (int) addend); - test("signed_plus_int", word, -((int) addend)); - test("signed_minus_int", word, -((int) addend)); - test("signed_plus_long", word, addend); - test("signed_minus_long", word, addend); - test("signed_plus_long", word, -addend); - test("signed_minus_long", word, -addend); - - test("and_int", word, (int) addend); - test("or_int", word, (int) addend); - test("and_int", word, -((int) addend)); - test("or_int", word, -((int) addend)); - test("and_long", word, addend); - test("or_long", word, addend); - test("and_long", word, -addend); - test("or_long", word, -addend); - } - } - } - - @LongTest - public void test_compare() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; - for (long word1 : words) { - for (long word2 : words) { - for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) { - test(method, word1, word2); - test(method, word2, word1); - } - } - } - } - - @Snippet - public static long unsigned_long(long word) { - return Word.unsigned(word).rawValue(); - } - - @Snippet - public static long unsigned_int(int word) { - return Word.unsigned(word).rawValue(); - } - - @Snippet - public static long signed_long(long word) { - return Word.signed(word).rawValue(); - } - - @Snippet - public static long signed_int(int word) { - return Word.signed(word).rawValue(); - } - - @Snippet - public static long unsigned_plus_int(long word, int addend) { - return Word.unsigned(word).add(addend).rawValue(); - } - - @Snippet - public static long unsigned_minus_int(long word, int addend) { - return Word.unsigned(word).subtract(addend).rawValue(); - } - - @Snippet - public static long unsigned_plus_long(long word, long addend) { - return Word.unsigned(word).add(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long unsigned_minus_long(long word, long addend) { - return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long signed_plus_int(long word, int addend) { - return Word.signed(word).add(addend).rawValue(); - } - - @Snippet - public static long signed_minus_int(long word, int addend) { - return Word.signed(word).subtract(addend).rawValue(); - } - - @Snippet - public static long signed_plus_long(long word, long addend) { - return Word.signed(word).add(Word.signed(addend)).rawValue(); - } - - @Snippet - public static long signed_minus_long(long word, long addend) { - return Word.signed(word).subtract(Word.signed(addend)).rawValue(); - } - - @Snippet - public static long signed_not(long word) { - return Word.signed(word).not().rawValue(); - } - - @Snippet - public static long unsigned_not(long word) { - return Word.unsigned(word).not().rawValue(); - } - - @Snippet - public static boolean aboveOrEqual(long word1, long word2) { - return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2)); - } - - @Snippet - public static boolean above(long word1, long word2) { - return Word.unsigned(word1).aboveThan(Word.unsigned(word2)); - } - - @Snippet - public static boolean belowOrEqual(long word1, long word2) { - return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2)); - } - - @Snippet - public static boolean below(long word1, long word2) { - return Word.unsigned(word1).belowThan(Word.unsigned(word2)); - } - - @Snippet - public static long and_int(long word, int addend) { - return Word.unsigned(word).and(addend).rawValue(); - } - - @Snippet - public static long or_int(long word, int addend) { - return Word.unsigned(word).or(addend).rawValue(); - } - - @Snippet - public static long and_long(long word, long addend) { - return Word.unsigned(word).and(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long or_long(long word, long addend) { - return Word.unsigned(word).or(Word.unsigned(addend)).rawValue(); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/overview.html --- a/graal/com.oracle.graal.snippets/overview.html Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ - - - - - - - - -Documentation for the com.oracle.graal.snippets project. - - - diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/ClassSubstitution.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/ClassSubstitution.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.lang.annotation.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Denotes a class that substitutes methods of another specified class. The substitute methods are - * exactly those annotated by {@link MethodSubstitution}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface ClassSubstitution { - - /** - * Specifies the original class. - *

- * If the default value is specified for this element, then a non-default value must be given - * for the {@link #className()} element. - */ - Class value() default ClassSubstitution.class; - - /** - * Specifies the original class. - *

- * This method is provided for cases where the original class is not accessible (according to - * Java language access control rules). - *

- * 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 ""; - - /** - * Determines if the substitutions are for classes that may not be part of the runtime. - * Substitutions for such classes are omitted if the original classes cannot be found. - */ - boolean optional() default false; - - /** - * Denotes a substitute method. A substitute method can call the original/substituted method by - * making a recursive call to itself. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public @interface MethodSubstitution { - - /** - * Gets the name of the original method. - *

- * If the default value is specified for this element, then the name of the original method - * is same as the substitute method. - */ - String value() default ""; - - /** - * Determines if the original method is static. - */ - boolean isStatic() default true; - - /** - * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the original - * method. - *

- * If the default value is specified for this element, then the signature of the original - * method is the same as the substitute method. - */ - String signature() default ""; - } - - /** - * Denotes a macro substitute method. This replaces a method invocation with an instance of the - * specified node class. - * - * A macro substitution can be combined with a normal substitution, so that the macro node can - * be replaced with the actual substitution code during lowering. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public @interface MacroSubstitution { - - /** - * Gets the name of the substituted method. - *

- * If the default value is specified for this element, then the name of the substituted - * method is same as the substitute method. - */ - String value() default ""; - - /** - * Determines if the substituted method is static. - */ - boolean isStatic() default true; - - /** - * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the substituted - * method. - *

- * If the default value is specified for this element, then the signature of the substituted - * method is the same as the substitute method. - */ - String signature() default ""; - - /** - * The node class with which the method invocation should be replaced. It needs to be a - * subclass of {@link FixedWithNextNode}, and it is expected to provide a public constructor - * that takes an InvokeNode as a parameter. For most cases this class should subclass - * {@link MacroNode} and use its constructor. - */ - Class macro(); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/DoubleSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/DoubleSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, 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.nodes.calc.*; -import com.oracle.graal.replacements.ClassSubstitution.*; - -/** - * Substitutions for {@link java.lang.Double} methods. - */ -@ClassSubstitution(java.lang.Double.class) -public class DoubleSubstitutions { - - private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN); - - @MethodSubstitution - public static long doubleToRawLongBits(double value) { - @JavacBug(id = 6995200) - Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value); - return result; - } - - // TODO This method is not necessary, since the JDK method does exactly this - @MethodSubstitution - public static long doubleToLongBits(double value) { - if (value != value) { - return NAN_RAW_LONG_BITS; - } else { - return doubleToRawLongBits(value); - } - } - - @MethodSubstitution - public static double longBitsToDouble(long bits) { - @JavacBug(id = 6995200) - Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits); - return result; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/FloatSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/FloatSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, 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.nodes.calc.*; -import com.oracle.graal.replacements.ClassSubstitution.*; - -/** - * Substitutions for {@link java.lang.Float} methods. - */ -@ClassSubstitution(java.lang.Float.class) -public class FloatSubstitutions { - - private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN); - - @MethodSubstitution - public static int floatToRawIntBits(float value) { - @JavacBug(id = 6995200) - Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value); - return result; - } - - // TODO This method is not necessary, since the JDK method does exactly this - @MethodSubstitution - public static int floatToIntBits(float value) { - if (value != value) { - return NAN_RAW_INT_BITS; - } else { - return floatToRawIntBits(value); - } - } - - @MethodSubstitution - public static float intBitsToFloat(int bits) { - @JavacBug(id = 6995200) - Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits); - return result; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/GraalIntrinsics.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/GraalIntrinsics.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2011, 2011, 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.phases.*; - -/** - * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. - */ -public class GraalIntrinsics { - - public static void installIntrinsics(ReplacementsInstaller installer) { - if (GraalOptions.Intrinsify) { - installer.installSubstitutions(MathSubstitutionsX86.class); - installer.installSubstitutions(DoubleSubstitutions.class); - installer.installSubstitutions(FloatSubstitutions.class); - installer.installSubstitutions(NodeClassSubstitutions.class); - installer.installSubstitutions(LongSubstitutions.class); - installer.installSubstitutions(IntegerSubstitutions.class); - installer.installSubstitutions(UnsignedMathSubstitutions.class); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2012, 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 static com.oracle.graal.nodes.calc.CompareNode.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.replacements.SnippetTemplate.*; - -/** - * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity - * in such a lowering derives from the fact that {@link InstanceOfNode} is a floating node. A - * snippet used to lower an {@link InstanceOfNode} will almost always incorporate control flow and - * replacing a floating node with control flow is not trivial. - *

- * The mechanism implemented in this class ensures that the graph for an instanceof snippet is - * instantiated once per {@link InstanceOfNode} being lowered. The result produced is then re-used - * by all usages of the node. Additionally, if there is a single usage that is an {@link IfNode}, - * the control flow in the snippet is connected directly to the true and false successors of the - * {@link IfNode}. This avoids materializing the instanceof test as a boolean which is then retested - * by the {@link IfNode}. - */ -public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates { - - public InstanceOfSnippetsTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { - super(runtime, assumptions, target, snippetsClass); - } - - /** - * The key and arguments used to retrieve and instantiate an instanceof snippet template. - */ - public static class KeyAndArguments { - - public final Key key; - public final Arguments arguments; - - public KeyAndArguments(Key key, Arguments arguments) { - this.key = key; - this.arguments = arguments; - } - - } - - /** - * Gets the key and arguments used to retrieve and instantiate an instanceof snippet template. - */ - protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); - - public void lower(FloatingNode instanceOf, LoweringTool tool) { - assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; - List usages = instanceOf.usages().snapshot(); - int nUsages = usages.size(); - - Instantiation instantiation = new Instantiation(); - for (Node usage : usages) { - final StructuredGraph graph = (StructuredGraph) usage.graph(); - - InstanceOfUsageReplacer replacer = createReplacer(instanceOf, tool, nUsages, instantiation, usage, graph); - - if (instantiation.isInitialized()) { - // No need to re-instantiate the snippet - just re-use its result - replacer.replaceUsingInstantiation(); - } else { - KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool); - SnippetTemplate template = cache.get(keyAndArguments.key, assumptions); - template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments); - } - } - - assert instanceOf.usages().isEmpty(); - if (!instanceOf.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(instanceOf); - } - } - - /** - * Gets the specific replacer object used to replace the usage of an instanceof node with the - * result of an instantiated instanceof snippet. - */ - protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { - InstanceOfUsageReplacer replacer; - if (usage instanceof IfNode) { - replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool); - } else { - assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; - ConditionalNode c = (ConditionalNode) usage; - replacer = new ConditionalUsageReplacer(instantiation, c.trueValue(), c.falseValue(), instanceOf, c); - } - return replacer; - } - - /** - * The result of an instantiating an instanceof snippet. This enables a snippet instantiation to - * be re-used which reduces compile time and produces better code. - */ - public static final class Instantiation { - - private PhiNode result; - private CompareNode condition; - private ValueNode trueValue; - private ValueNode falseValue; - - /** - * Determines if the instantiation has occurred. - */ - boolean isInitialized() { - return result != null; - } - - void initialize(PhiNode phi, ValueNode t, ValueNode f) { - assert !isInitialized(); - this.result = phi; - this.trueValue = t; - this.falseValue = f; - } - - /** - * Gets the result of this instantiation as a condition. - * - * @param testValue the returned condition is true if the result is equal to this value - */ - CompareNode asCondition(ValueNode testValue) { - assert isInitialized(); - if (condition == null || condition.y() != testValue) { - // Re-use previously generated condition if the trueValue for the test is the same - condition = createCompareNode(Condition.EQ, result, testValue); - } - return condition; - } - - /** - * Gets the result of the instantiation as a materialized value. - * - * @param t the true value for the materialization - * @param f the false value for the materialization - */ - ValueNode asMaterialization(ValueNode t, ValueNode f) { - assert isInitialized(); - if (t == this.trueValue && f == this.falseValue) { - // Can simply use the phi result if the same materialized values are expected. - return result; - } else { - return t.graph().unique(new ConditionalNode(asCondition(trueValue), t, f)); - } - } - } - - /** - * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. - */ - public abstract static class InstanceOfUsageReplacer implements UsageReplacer { - - public final Instantiation instantiation; - public final FloatingNode instanceOf; - public final ValueNode trueValue; - public final ValueNode falseValue; - - public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) { - assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; - this.instantiation = instantiation; - this.instanceOf = instanceOf; - this.trueValue = trueValue; - this.falseValue = falseValue; - } - - /** - * Does the replacement based on a previously snippet instantiation. - */ - public abstract void replaceUsingInstantiation(); - } - - /** - * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or - * {@link InstanceOfDynamicNode}. - */ - public static class IfUsageReplacer extends InstanceOfUsageReplacer { - - private final boolean solitaryUsage; - private final IfNode usage; - private final boolean sameBlock; - - public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) { - super(instantiation, instanceOf, trueValue, falseValue); - this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf); - this.solitaryUsage = solitaryUsage; - this.usage = usage; - } - - @Override - public void replaceUsingInstantiation() { - usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue)); - } - - private boolean usageFollowsInstantiation() { - return instantiation.result != null && instantiation.result.merge().next() == usage; - } - - @Override - public void replace(ValueNode oldNode, ValueNode newNode) { - assert newNode instanceof PhiNode; - assert oldNode == instanceOf; - if (sameBlock && solitaryUsage && usageFollowsInstantiation()) { - removeIntermediateMaterialization(newNode); - } else { - newNode.inferStamp(); - instantiation.initialize((PhiNode) newNode, trueValue, falseValue); - usage.replaceFirstInput(oldNode, instantiation.asCondition(trueValue)); - } - } - - /** - * Directly wires the incoming edges of the merge at the end of the snippet to the outgoing - * edges of the IfNode that uses the materialized result. - */ - private void removeIntermediateMaterialization(ValueNode newNode) { - IfNode ifNode = usage; - PhiNode phi = (PhiNode) newNode; - MergeNode merge = phi.merge(); - assert merge.stateAfter() == null; - - List mergePredecessors = merge.cfgPredecessors().snapshot(); - assert phi.valueCount() == mergePredecessors.size(); - - List falseEnds = new ArrayList<>(mergePredecessors.size()); - List trueEnds = new ArrayList<>(mergePredecessors.size()); - - int endIndex = 0; - for (EndNode end : mergePredecessors) { - ValueNode endValue = phi.valueAt(endIndex++); - if (endValue == trueValue) { - trueEnds.add(end); - } else { - assert endValue == falseValue; - falseEnds.add(end); - } - } - - BeginNode trueSuccessor = ifNode.trueSuccessor(); - BeginNode falseSuccessor = ifNode.falseSuccessor(); - ifNode.setTrueSuccessor(null); - ifNode.setFalseSuccessor(null); - - connectEnds(merge, trueEnds, trueSuccessor); - connectEnds(merge, falseEnds, falseSuccessor); - - GraphUtil.killCFG(merge); - GraphUtil.killCFG(ifNode); - - assert !merge.isAlive() : merge; - assert !phi.isAlive() : phi; - } - - private static void connectEnds(MergeNode merge, List ends, BeginNode successor) { - if (ends.size() == 0) { - // InstanceOf has been lowered to always true or always false - this successor is - // therefore unreachable. - GraphUtil.killCFG(successor); - } else if (ends.size() == 1) { - EndNode end = ends.get(0); - ((FixedWithNextNode) end.predecessor()).setNext(successor); - merge.removeEnd(end); - GraphUtil.killCFG(end); - } else { - assert ends.size() > 1; - MergeNode newMerge = merge.graph().add(new MergeNode()); - - for (EndNode end : ends) { - newMerge.addForwardEnd(end); - } - newMerge.setNext(successor); - } - } - } - - /** - * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or - * {@link InstanceOfDynamicNode}. - */ - public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer { - - public final ConditionalNode usage; - - public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) { - super(instantiation, instanceOf, trueValue, falseValue); - this.usage = usage; - } - - @Override - public void replaceUsingInstantiation() { - ValueNode newValue = instantiation.asMaterialization(trueValue, falseValue); - usage.replaceAtUsages(newValue); - usage.clearInputs(); - assert usage.usages().isEmpty(); - GraphUtil.killWithUnusedFloatingInputs(usage); - } - - @Override - public void replace(ValueNode oldNode, ValueNode newNode) { - assert newNode instanceof PhiNode; - assert oldNode == instanceOf; - newNode.inferStamp(); - instantiation.initialize((PhiNode) newNode, trueValue, falseValue); - usage.replaceAtUsages(newNode); - usage.clearInputs(); - assert usage.usages().isEmpty(); - GraphUtil.killWithUnusedFloatingInputs(usage); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/IntegerSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/IntegerSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.replacements.ClassSubstitution.*; -import com.oracle.graal.replacements.nodes.*; - -@ClassSubstitution(Integer.class) -public class IntegerSubstitutions { - - @MethodSubstitution - public static int reverseBytes(int i) { - return ReverseBytesNode.reverse(i); - } - - @MethodSubstitution - public static int numberOfLeadingZeros(int i) { - if (i == 0) { - return 32; - } - return 31 - BitScanReverseNode.scan(i); - } - - @MethodSubstitution - public static int numberOfTrailingZeros(int i) { - if (i == 0) { - return 32; - } - return BitScanForwardNode.scan(i); - } - - @MethodSubstitution - public static int bitCount(int i) { - return BitCountNode.bitCount(i); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/JavacBug.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/JavacBug.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2011, 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; - -/** - * Used to indicate that an otherwise strange looking code pattern is required to work around a bug - * in javac. - */ -public @interface JavacBug { - - /** - * A description of the bug. Only really useful if there is no existing entry for the bug in the - * Bug Database. - */ - String value() default ""; - - /** - * An identifier in the Bug Database. - */ - int id() default 0; -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/Log.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/Log.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2012, 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 java.io.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; - -//JaCoCo Exclude - -/** - * Provides {@link PrintStream}-like logging facility. This should only be used in - * {@linkplain Snippet snippets}. - */ -public final class Log { - - public static final Descriptor LOG_PRIMITIVE = new Descriptor("logPrimitive", false, void.class, int.class, long.class, boolean.class); - public static final Descriptor LOG_OBJECT = new Descriptor("logObject", false, void.class, Object.class, int.class); - public static final Descriptor LOG_PRINTF = new Descriptor("logPrintf", false, void.class, Object.class, long.class, long.class, long.class); - - // Note: Must be kept in sync with constants in c1_Runtime1.hpp - private static final int LOG_OBJECT_NEWLINE = 0x01; - private static final int LOG_OBJECT_STRING = 0x02; - private static final int LOG_OBJECT_ADDRESS = 0x04; - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void log(@ConstantNodeParameter Descriptor logObject, Object object, int flags); - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void log(@ConstantNodeParameter Descriptor logPrimitive, int typeChar, long value, boolean newline); - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void printf(@ConstantNodeParameter Descriptor logPrintf, String format, long v1, long v2, long v3); - - public static void print(boolean value) { - log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, false); - } - - public static void print(byte value) { - log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, false); - } - - public static void print(char value) { - log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, false); - } - - public static void print(short value) { - log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, false); - } - - public static void print(int value) { - log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, false); - } - - public static void print(long value) { - log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, false); - } - - /** - * Prints a formatted string to the log stream. - * - * @param format a C style printf format value that can contain at most one conversion specifier - * (i.e., a sequence of characters starting with '%'). - * @param value the value associated with the conversion specifier - */ - public static void printf(String format, long value) { - printf(LOG_PRINTF, format, value, 0L, 0L); - } - - public static void printf(String format, long v1, long v2) { - printf(LOG_PRINTF, format, v1, v2, 0L); - } - - public static void printf(String format, long v1, long v2, long v3) { - printf(LOG_PRINTF, format, v1, v2, v3); - } - - public static void print(float value) { - if (Float.isNaN(value)) { - print("NaN"); - } else if (value == Float.POSITIVE_INFINITY) { - print("Infinity"); - } else if (value == Float.NEGATIVE_INFINITY) { - print("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), false); - } - } - - public static void print(double value) { - if (Double.isNaN(value)) { - print("NaN"); - } else if (value == Double.POSITIVE_INFINITY) { - print("Infinity"); - } else if (value == Double.NEGATIVE_INFINITY) { - print("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false); - } - } - - public static void print(String value) { - log(LOG_OBJECT, value, LOG_OBJECT_STRING); - } - - public static void printAddress(Object o) { - log(LOG_OBJECT, o, LOG_OBJECT_ADDRESS); - } - - public static void printObject(Object o) { - log(LOG_OBJECT, o, 0); - } - - public static void println(boolean value) { - log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, true); - } - - public static void println(byte value) { - log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, true); - } - - public static void println(char value) { - log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, true); - } - - public static void println(short value) { - log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, true); - } - - public static void println(int value) { - log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, true); - } - - public static void println(long value) { - log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, true); - } - - public static void println(float value) { - if (Float.isNaN(value)) { - println("NaN"); - } else if (value == Float.POSITIVE_INFINITY) { - println("Infinity"); - } else if (value == Float.NEGATIVE_INFINITY) { - println("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), true); - } - } - - public static void println(double value) { - if (Double.isNaN(value)) { - println("NaN"); - } else if (value == Double.POSITIVE_INFINITY) { - println("Infinity"); - } else if (value == Double.NEGATIVE_INFINITY) { - println("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true); - } - } - - public static void println(String value) { - log(LOG_OBJECT, value, LOG_OBJECT_NEWLINE | LOG_OBJECT_STRING); - } - - public static void printlnAddress(Object o) { - log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE | LOG_OBJECT_ADDRESS); - } - - public static void printlnObject(Object o) { - log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE); - } - - public static void println() { - println(""); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/LongSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/LongSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.replacements.ClassSubstitution.*; -import com.oracle.graal.replacements.nodes.*; - -@ClassSubstitution(Long.class) -public class LongSubstitutions { - - @MethodSubstitution - public static long reverseBytes(long i) { - return ReverseBytesNode.reverse(i); - } - - @MethodSubstitution - public static int numberOfLeadingZeros(long i) { - if (i == 0) { - return 64; - } - return 63 - BitScanReverseNode.scan(i); - } - - @MethodSubstitution - public static int numberOfTrailingZeros(long i) { - if (i == 0) { - return 64; - } - return BitScanForwardNode.scan(i); - } - - @MethodSubstitution - public static int bitCount(long i) { - return BitCountNode.bitCount(i); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/MathSubstitutionsX86.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2011, 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.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.replacements.ClassSubstitution.*; -import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.replacements.nodes.MathIntrinsicNode.*; - -/** - * Substitutions for {@link java.lang.Math} methods. - */ -@ClassSubstitution(java.lang.Math.class) -public class MathSubstitutionsX86 { - - private static final double PI_4 = 0.7853981633974483; - - @MethodSubstitution - public static double abs(double x) { - return MathIntrinsicNode.compute(x, Operation.ABS); - } - - @MethodSubstitution - public static double sqrt(double x) { - return MathIntrinsicNode.compute(x, Operation.SQRT); - } - - @MethodSubstitution - public static double log(double x) { - return MathIntrinsicNode.compute(x, Operation.LOG); - } - - @MethodSubstitution - public static double log10(double x) { - return MathIntrinsicNode.compute(x, Operation.LOG10); - } - - // NOTE on snippets below: - // Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the - // exact result, but x87 trigonometric FPU instructions are only that - // accurate within [-pi/4, pi/4]. Examine the passed value and provide - // a slow path for inputs outside of that interval. - - @MethodSubstitution - public static double sin(double x) { - if (abs(x) < PI_4) { - return MathIntrinsicNode.compute(x, Operation.SIN); - } else { - return callDouble(ARITHMETIC_SIN, x); - } - } - - @MethodSubstitution - public static double cos(double x) { - if (abs(x) < PI_4) { - return MathIntrinsicNode.compute(x, Operation.COS); - } else { - return callDouble(ARITHMETIC_COS, x); - } - } - - @MethodSubstitution - public static double tan(double x) { - if (abs(x) < PI_4) { - return MathIntrinsicNode.compute(x, Operation.TAN); - } else { - return callDouble(ARITHMETIC_TAN, x); - } - } - - public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class); - public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class); - public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class); - - @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) - public static native double callDouble(@ConstantNodeParameter Descriptor descriptor, double value); -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/NodeClassSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/NodeClassSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2011, 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.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.replacements.ClassSubstitution.*; - -/** - * Substitutions for improving the performance of some critical methods in {@link NodeClass} - * methods. These substitutions improve the performance by forcing the relevant methods to be - * inlined (intrinsification being a special form of inlining) and removing a checked cast. The - * latter cannot be done directly in Java code as {@link UnsafeCastNode} is not available to the - * project containing {@link NodeClass}. - */ -@ClassSubstitution(NodeClass.class) -public class NodeClassSubstitutions { - - @MethodSubstitution - private static Node getNode(Node node, long offset) { - return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false); - } - - @MethodSubstitution - private static NodeList getNodeList(Node node, long offset) { - return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false); - } - - @MethodSubstitution - private static void putNode(Node node, long offset, Node value) { - UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); - } - - @MethodSubstitution - private static void putNodeList(Node node, long offset, NodeList value) { - UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); - } - -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2011, 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 static com.oracle.graal.api.meta.MetaUtil.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.Snippet.*; - -/** - * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with - * {@link Fold} with the result of invoking the annotated method via reflection. - */ -public class NodeIntrinsificationPhase extends Phase { - - private final MetaAccessProvider runtime; - private final BoxingMethodPool pool; - - public NodeIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { - this.runtime = runtime; - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke i : graph.getInvokes()) { - if (i.callTarget() instanceof MethodCallTargetNode) { - tryIntrinsify(i); - } - } - } - - public static Class[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) { - int count = signature.getParameterCount(false); - Class[] result = new Class[count]; - for (int i = 0; i < result.length; ++i) { - result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); - } - return result; - } - - private boolean tryIntrinsify(Invoke invoke) { - ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); - NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); - ResolvedJavaType declaringClass = target.getDeclaringClass(); - if (intrinsic != null) { - assert target.getAnnotation(Fold.class) == null; - - Class[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); - ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass); - - // Prepare the arguments for the reflective constructor call on the node class. - Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); - if (nodeConstructorArguments == null) { - return false; - } - - // Create the new node instance. - Class c = getNodeClass(target, intrinsic); - Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments); - - // Replace the invoke with the new node. - invoke.node().graph().add(newInstance); - invoke.intrinsify(newInstance); - - // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(newInstance); - } else if (target.getAnnotation(Fold.class) != null) { - Class[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); - - // Prepare the arguments for the reflective method call - Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); - if (arguments == null) { - return false; - } - Object receiver = null; - if (!invoke.methodCallTarget().isStatic()) { - receiver = arguments[0]; - arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); - } - - // Call the method - Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, Thread.currentThread().getContextClassLoader()), target.getName(), parameterTypes, - receiver, arguments); - - if (constant != null) { - // Replace the invoke with the result of the call - ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.node().graph()); - invoke.intrinsify(node); - - // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(node); - } else { - // Remove the invoke - invoke.intrinsify(null); - } - } - return true; - } - - /** - * Converts the arguments of an invoke node to object values suitable for use as the arguments - * to a reflective invocation of a Java constructor or method. - * - * @param folding specifies if the invocation is for handling a {@link Fold} annotation - * @return the arguments for the reflective invocation or null if an argument of {@code invoke} - * that is expected to be constant isn't - */ - private Object[] prepareArguments(Invoke invoke, Class[] parameterTypes, ResolvedJavaMethod target, boolean folding) { - NodeInputList arguments = invoke.callTarget().arguments(); - Object[] reflectionCallArguments = new Object[arguments.size()]; - for (int i = 0; i < reflectionCallArguments.length; ++i) { - int parameterIndex = i; - if (!invoke.methodCallTarget().isStatic()) { - parameterIndex--; - } - ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); - if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { - if (!(argument instanceof ConstantNode)) { - return null; - } - ConstantNode constantNode = (ConstantNode) argument; - Constant constant = constantNode.asConstant(); - Object o = constant.asBoxedValue(); - if (o instanceof Class) { - reflectionCallArguments[i] = runtime.lookupJavaType((Class) o); - parameterTypes[i] = ResolvedJavaType.class; - } else { - if (parameterTypes[i] == boolean.class) { - reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); - } else if (parameterTypes[i] == byte.class) { - reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); - } else if (parameterTypes[i] == short.class) { - reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); - } else if (parameterTypes[i] == char.class) { - reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); - } else { - reflectionCallArguments[i] = o; - } - } - } else { - reflectionCallArguments[i] = argument; - parameterTypes[i] = ValueNode.class; - } - } - return reflectionCallArguments; - } - - private static Class getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { - Class result = intrinsic.value(); - if (result == NodeIntrinsic.class) { - return getMirrorOrFail(target.getDeclaringClass(), Thread.currentThread().getContextClassLoader()); - } - assert Node.class.isAssignableFrom(result); - return result; - } - - private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) { - if (parameterIndex >= 0) { - Type type = target.getGenericParameterTypes()[parameterIndex]; - if (type instanceof TypeVariable) { - TypeVariable typeVariable = (TypeVariable) type; - if (typeVariable.getBounds().length == 1) { - Type boundType = typeVariable.getBounds()[0]; - if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) { - // Unbound generic => try boxing elimination - if (node.usages().count() == 2) { - if (node instanceof Invoke) { - Invoke invokeNode = (Invoke) node; - MethodCallTargetNode callTarget = invokeNode.methodCallTarget(); - if (pool.isBoxingMethod(callTarget.targetMethod())) { - FrameState stateAfter = invokeNode.stateAfter(); - assert stateAfter.usages().count() == 1; - invokeNode.node().replaceAtUsages(null); - ValueNode result = callTarget.arguments().get(0); - StructuredGraph graph = (StructuredGraph) node.graph(); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - stateAfter.safeDelete(); - GraphUtil.propagateKill(callTarget); - return result; - } - } - } - } - } - } - } - return node; - } - - private static Class asBoxedType(Class type) { - if (!type.isPrimitive()) { - return type; - } - - if (Boolean.TYPE == type) { - return Boolean.class; - } - if (Character.TYPE == type) { - return Character.class; - } - if (Byte.TYPE == type) { - return Byte.class; - } - if (Short.TYPE == type) { - return Short.class; - } - if (Integer.TYPE == type) { - return Integer.class; - } - if (Long.TYPE == type) { - return Long.class; - } - if (Float.TYPE == type) { - return Float.class; - } - assert Double.TYPE == type; - return Double.class; - } - - static final int VARARGS = 0x00000080; - - private static Node createNodeInstance(Class nodeClass, Class[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Object[] nodeConstructorArguments) { - Object[] arguments = null; - Constructor constructor = null; - nextConstructor: for (Constructor c : nodeClass.getDeclaredConstructors()) { - Class[] signature = c.getParameterTypes(); - if ((c.getModifiers() & VARARGS) != 0) { - int fixedArgs = signature.length - 1; - if (parameterTypes.length < fixedArgs) { - continue nextConstructor; - } - - for (int i = 0; i < fixedArgs; i++) { - if (!parameterTypes[i].equals(signature[i])) { - continue nextConstructor; - } - } - - Class componentType = signature[fixedArgs].getComponentType(); - assert componentType != null : "expected last parameter of varargs constructor " + c + " to be an array type"; - Class boxedType = asBoxedType(componentType); - for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { - if (!boxedType.isInstance(nodeConstructorArguments[i])) { - continue nextConstructor; - } - } - - arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); - int varargsLength = nodeConstructorArguments.length - fixedArgs; - Object varargs = Array.newInstance(componentType, varargsLength); - for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { - Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]); - } - arguments[fixedArgs] = varargs; - constructor = c; - break; - } else if (Arrays.equals(parameterTypes, signature)) { - arguments = nodeConstructorArguments; - constructor = c; - break; - } - } - if (constructor == null) { - throw new GraalInternalError("Could not find constructor in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes)); - } - constructor.setAccessible(true); - try { - ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments); - if (setStampFromReturnType) { - if (returnType.getKind() == Kind.Object) { - intrinsicNode.setStamp(StampFactory.declared(returnType)); - } else { - intrinsicNode.setStamp(StampFactory.forKind(returnType.getKind())); - } - } - return intrinsicNode; - } catch (Exception e) { - throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); - } - } - - /** - * Calls a Java method via reflection. - */ - private static Constant callMethod(Kind returnKind, Class holder, String name, Class[] parameterTypes, Object receiver, Object[] arguments) { - Method method; - try { - method = holder.getDeclaredMethod(name, parameterTypes); - method.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - try { - Object result = method.invoke(receiver, arguments); - if (result == null) { - return null; - } - return Constant.forBoxed(returnKind, result); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static String sourceLocation(Node n) { - String loc = GraphUtil.approxSourceLocation(n); - return loc == null ? "" : loc; - } - - public void cleanUpReturnCheckCast(Node newInstance) { - if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { - StructuredGraph graph = (StructuredGraph) newInstance.graph(); - for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { - for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) { - graph.replaceFloating(vpn, checkCastNode); - } - for (Node checkCastUsage : checkCastNode.usages().snapshot()) { - if (checkCastUsage instanceof ValueAnchorNode) { - ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; - graph.removeFixed(valueAnchorNode); - } else if (checkCastUsage instanceof MethodCallTargetNode) { - MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; - if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) { - Invoke invokeNode = checkCastCallTarget.invoke(); - invokeNode.node().replaceAtUsages(newInstance); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - checkCastCallTarget.safeDelete(); - } else { - assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + - " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + - checkCastCallTarget.targetMethod(); - checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); - } - } else if (checkCastUsage instanceof FrameState) { - checkCastUsage.replaceFirstInput(checkCastNode, null); - } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { - checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); - } else { - assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); - } - } - FixedNode next = checkCastNode.next(); - checkCastNode.setNext(null); - checkCastNode.replaceAtPredecessor(next); - GraphUtil.killCFG(checkCastNode); - } - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2011, 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.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.Snippet.*; - -/** - * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods. - */ -public class NodeIntrinsificationVerificationPhase extends Phase { - - public static boolean verify(StructuredGraph graph) { - new NodeIntrinsificationVerificationPhase().apply(graph); - return true; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke i : graph.getInvokes()) { - if (i.callTarget() instanceof MethodCallTargetNode) { - checkInvoke(i); - } - } - } - - private static void checkInvoke(Invoke invoke) { - ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); - NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); - if (intrinsic != null) { - throw new GraalInternalError("Illegal call to node intrinsic in " + invoke.graph() + ": " + invoke); - } else if (target.getAnnotation(Fold.class) != null) { - throw new GraalInternalError("Illegal call to foldable method in " + invoke.graph() + ": " + invoke); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/ReplacementsInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/ReplacementsInstaller.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,406 +0,0 @@ -/* - * Copyright (c) 2011, 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 static com.oracle.graal.api.meta.MetaUtil.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.ClassSubstitution.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.word.phases.*; - -/** - * Utility for managing the pre-processing and installation of replacements. Replacements are either - * {@linkplain Snippets snippets}, {@linkplain MethodSubstitution method substitutions} or - * {@link MacroSubstitution macro substitutions}. - */ -public class ReplacementsInstaller { - - protected final MetaAccessProvider runtime; - protected final TargetDescription target; - protected final Assumptions assumptions; - protected final BoxingMethodPool pool; - private final Thread owner; - - /** - * A graph cache used by this installer to avoid using the compiler storage for each method - * processed during snippet installation. Without this, all processed methods are to be - * determined as {@linkplain InliningUtil#canIntrinsify intrinsifiable}. - */ - private final Map graphCache; - - public ReplacementsInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - this.pool = new BoxingMethodPool(runtime); - this.graphCache = new HashMap<>(); - this.owner = Thread.currentThread(); - } - - /** - * Finds all the snippet methods in a given class, builds a graph for them and installs the - * graph with the key value of {@code Graph.class} in the - * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. - */ - public void installSnippets(Class snippets) { - for (Method method : snippets.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null) { - int modifiers = method.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); - assert snippet.getCompilerStorage().get(Graph.class) == null : method; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); - // System.out.println("snippet: " + graph); - snippet.getCompilerStorage().put(Graph.class, graph); - } - } - } - - /** - * Finds all the methods in a given class annotated with {@link MethodSubstitution} or - * {@link MacroSubstitution}. It builds graphs for the former and installs them in the - * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of the original (i.e., - * substituted) method with a key of {@code Graph.class}. For the latter, the denoted - * {@linkplain MacroSubstitution#macro() macro} node type is install in the compiler storage - * with a key of {@code Node.class}. - */ - public void installSubstitutions(Class substitutions) { - assert owner == Thread.currentThread() : "substitution installation must be single threaded"; - ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); - assert classSubstitution != null; - assert !Snippets.class.isAssignableFrom(substitutions); - for (Method substituteMethod : substitutions.getDeclaredMethods()) { - MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); - MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); - if (methodSubstitution == null && macroSubstitution == null) { - continue; - } - - int modifiers = substituteMethod.getModifiers(); - if (!Modifier.isStatic(modifiers)) { - throw new RuntimeException("Substitution methods must be static: " + substituteMethod); - } - - if (methodSubstitution != null) { - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod); - } - String originalName = originalName(substituteMethod, methodSubstitution.value()); - Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - if (originalMethod != null) { - installMethodSubstitution(originalMethod, substituteMethod); - } - } - if (macroSubstitution != null) { - String originalName = originalName(substituteMethod, macroSubstitution.value()); - Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - if (originalMethod != null) { - installMacroSubstitution(originalMethod, macroSubstitution.macro()); - } - } - } - } - - // These fields are used to detect calls from the substitute method to the original method. - ResolvedJavaMethod substitute; - ResolvedJavaMethod original; - boolean substituteCallsOriginal; - - /** - * Installs a method substitution. - * - * @param originalMethod a method or constructor being substituted - * @param substituteMethod the substitute method - */ - protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { - substitute = runtime.lookupJavaMethod(substituteMethod); - if (originalMethod instanceof Method) { - original = runtime.lookupJavaMethod((Method) originalMethod); - } else { - original = runtime.lookupJavaConstructor((Constructor) originalMethod); - } - try { - Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); - StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute)); - Object oldValue = original.getCompilerStorage().put(Graph.class, graph); - assert oldValue == null; - } finally { - substitute = null; - original = null; - substituteCallsOriginal = false; - } - } - - /** - * Installs a macro substitution. - * - * @param originalMethod a method or constructor being substituted - * @param macro the substitute macro node class - */ - protected void installMacroSubstitution(Member originalMethod, Class macro) { - ResolvedJavaMethod originalJavaMethod; - if (originalMethod instanceof Method) { - originalJavaMethod = runtime.lookupJavaMethod((Method) originalMethod); - } else { - originalJavaMethod = runtime.lookupJavaConstructor((Constructor) originalMethod); - } - Object oldValue = originalJavaMethod.getCompilerStorage().put(Node.class, macro); - assert oldValue == null; - } - - private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(runtime, pool); - } - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - /** - * Does final processing of a snippet graph. - */ - protected void finalizeGraph(ResolvedJavaMethod method, StructuredGraph graph) { - new NodeIntrinsificationPhase(runtime, pool).apply(graph); - assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); - - new SnippetFrameStateCleanupPhase().apply(graph); - new DeadCodeEliminationPhase().apply(graph); - - new InsertStateAfterPlaceholderPhase().apply(graph); - } - - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable() { - - @Override - public StructuredGraph call() throws Exception { - StructuredGraph graph = parseGraph(method, policy); - - finalizeGraph(method, graph); - - Debug.dump(graph, "%s: Final", method.getName()); - - return graph; - } - }); - } - - private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - StructuredGraph graph = graphCache.get(method); - if (graph == null) { - graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); - graphCache.put(method, graph); - } - return graph; - } - - /** - * Builds the initial graph for a snippet. - */ - protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod method) { - final StructuredGraph graph = new StructuredGraph(method); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); - - Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); - - new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); - new NodeIntrinsificationPhase(runtime, pool).apply(graph); - - return graph; - } - - /** - * Called after a graph is inlined. - * - * @param caller the graph into which {@code callee} was inlined - * @param callee the graph that was inlined into {@code caller} - */ - protected void afterInline(StructuredGraph caller, StructuredGraph callee) { - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller); - new CanonicalizerPhase(runtime, assumptions).apply(caller); - } - } - - /** - * Called after all inlining for a given graph is complete. - */ - protected void afterInlining(StructuredGraph graph) { - new NodeIntrinsificationPhase(runtime, pool).apply(graph); - - new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - } - } - - private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : method; - final StructuredGraph graph = buildInitialGraph(method); - - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (callee == substitute) { - final StructuredGraph originalGraph = new StructuredGraph(original); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); - InliningUtil.inline(invoke, originalGraph, true); - - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, originalGraph); - substituteCallsOriginal = true; - } else { - if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) { - StructuredGraph targetGraph = parseGraph(callee, policy); - InliningUtil.inline(invoke, targetGraph, true); - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, targetGraph); - } - } - } - - afterInlining(graph); - - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } - - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(graph); - new ComputeProbabilityPhase().apply(graph); - } - return graph; - } - - private static String originalName(Method substituteMethod, String methodSubstitution) { - if (methodSubstitution.isEmpty()) { - return substituteMethod.getName(); - } else { - return methodSubstitution; - } - } - - /** - * Resolves a name to a class. - * - * @param className the name of the class to resolve - * @param optional if true, resolution failure returns null - * @return the resolved class or null if resolution fails and {@code optional} is true - */ - private static Class resolveType(String className, boolean optional) { - try { - // Need to use launcher class path to handle classes - // that are not on the boot class path - ClassLoader cl = Launcher.getLauncher().getClassLoader(); - return Class.forName(className, false, cl); - } catch (ClassNotFoundException e) { - if (optional) { - return null; - } - throw new GraalInternalError("Could not resolve type " + className); - } - } - - private static Class resolveType(JavaType type) { - JavaType base = type; - int dimensions = 0; - while (base.getComponentType() != null) { - base = base.getComponentType(); - dimensions++; - } - - Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); - return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); - } - - private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) { - Class[] parameters; - if (methodSubstitution.isEmpty()) { - parameters = substituteMethod.getParameterTypes(); - if (!isStatic) { - assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; - parameters = Arrays.copyOfRange(parameters, 1, parameters.length); - } - } else { - Signature signature = runtime.parseMethodDescriptor(methodSubstitution); - parameters = new Class[signature.getParameterCount(false)]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = resolveType(signature.getParameterType(i, null)); - } - } - return parameters; - } - - private static Member originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { - Class originalClass = classSubstitution.value(); - if (originalClass == ClassSubstitution.class) { - originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); - if (originalClass == null) { - // optional class was not found - return null; - } - } - try { - if (name.equals("")) { - return originalClass.getDeclaredConstructor(parameters); - } else { - return originalClass.getDeclaredMethod(name, parameters); - } - } catch (NoSuchMethodException | SecurityException e) { - throw new GraalInternalError(e); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/Snippet.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.lang.annotation.*; -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; - -/** - * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering - * nodes that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode). - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface Snippet { - - /** - * Specifies the class defining the inlining policy for this snippet. A - * {@linkplain DefaultSnippetInliningPolicy default} policy is used if none is supplied. - */ - Class inlining() default SnippetInliningPolicy.class; - - /** - * Guides inlining decisions used when installing a snippet. - */ - public interface SnippetInliningPolicy { - - /** - * Determines if {@code method} should be inlined into {@code caller}. - */ - boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); - } - - /** - * The default inlining policy which inlines everything except for methods in any of the - * following categories. - *

    - *
  • {@linkplain Fold foldable} methods
  • - *
  • {@linkplain NodeIntrinsic node intrinsics}
  • - *
  • native methods
  • - *
  • constructors of {@link Throwable} classes
  • - *
- */ - public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { - - private final MetaAccessProvider metaAccess; - private final BoxingMethodPool pool; - - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { - this.metaAccess = metaAccess; - this.pool = pool; - } - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (Modifier.isNative(method.getModifiers())) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { - if (method.getName().equals("")) { - return false; - } - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - if (pool.isSpecialMethod(method)) { - return false; - } - return true; - } - } - - /** - * Annotates a method replaced by a compile-time constant. A (resolved) call to the annotated - * method is replaced with a constant obtained by calling the annotated method via reflection. - * - * All arguments to such a method (including the receiver if applicable) must be compile-time - * constants. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public static @interface Fold { - } - - /** - * Denotes a snippet parameter that will be bound during snippet template - * {@linkplain SnippetTemplate#instantiate instantiation}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface Parameter { - - /** - * The name of this parameter. - */ - String value(); - } - - /** - * Denotes a snippet parameter representing 0 or more arguments that will be bound during - * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet - * template creation, its value must be an array whose length specifies the number of arguments - * (the contents of the array are ignored) bound to the parameter during - * {@linkplain SnippetTemplate#instantiate instantiation}. - * - * Such a parameter must be used in a counted loop in the snippet preceded by a call to - * {@link ExplodeLoopNode#explodeLoop()}. The counted looped must be a standard iteration over - * all the loop's elements (i.e. {@code for (T e : arr) ... }). - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface VarargsParameter { - - /** - * The name of this parameter. - */ - String value(); - } - - /** - * Denotes a snippet parameter that will bound to a constant value during snippet template - * {@linkplain SnippetTemplate#instantiate instantiation}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface ConstantParameter { - - /** - * The name of this constant. - */ - String value(); - } - - /** - * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. - */ - public static class Varargs { - - private final Object args; - private final Class argType; - private final int length; - private final Stamp argStamp; - - public static Varargs vargargs(Object array, Stamp argStamp) { - return new Varargs(array, argStamp); - } - - public Varargs(Object array, Stamp argStamp) { - assert array != null; - this.argType = array.getClass().getComponentType(); - this.argStamp = argStamp; - assert this.argType != null; - this.length = java.lang.reflect.Array.getLength(array); - this.args = array; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Varargs) { - Varargs other = (Varargs) obj; - return other.argType == argType && other.length == length; - } - return false; - } - - public Object getArray() { - return args; - } - - public Stamp getArgStamp() { - return argStamp; - } - - @Override - public int hashCode() { - return argType.hashCode() ^ length; - } - - @Override - public String toString() { - return argType.getName() + "[" + length + "]"; - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/SnippetCounter.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/SnippetCounter.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2012, 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; - -//JaCoCo Exclude - -import static com.oracle.graal.graph.FieldIntrospection.*; - -import java.io.*; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering - * snippet specific metrics. - */ -public class SnippetCounter implements Comparable { - - /** - * A group of related counters. - */ - public static class Group { - - final String name; - final List counters; - - public Group(String name) { - this.name = name; - this.counters = new ArrayList<>(); - } - - @Override - public synchronized String toString() { - Collections.sort(counters); - - long total = 0; - int maxNameLen = 0; - for (SnippetCounter c : counters) { - total += c.value; - maxNameLen = Math.max(c.name.length(), maxNameLen); - } - - StringBuilder buf = new StringBuilder(String.format("Counters: %s%n", name)); - - for (SnippetCounter c : counters) { - double percent = total == 0D ? 0D : ((double) (c.value * 100)) / total; - buf.append(String.format(" %" + maxNameLen + "s: %5.2f%%%10d // %s%n", c.name, percent, c.value, c.description)); - } - return buf.toString(); - } - } - - /** - * Sorts counters in descending order of their {@linkplain #value() values}. - */ - @Override - public int compareTo(SnippetCounter o) { - if (value > o.value) { - return -1; - } else if (o.value < value) { - return 1; - } - return 0; - } - - private static final List groups = new ArrayList<>(); - - private final Group group; - private final int index; - private final String name; - private final String description; - private long value; - - @Fold - private static int countOffset() { - try { - return (int) unsafe.objectFieldOffset(SnippetCounter.class.getDeclaredField("value")); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - /** - * Creates a counter. - * - * @param group the group to which the counter belongs. If this is null, the newly created - * counter is disabled and {@linkplain #inc() incrementing} is a no-op. - * @param name the name of the counter - * @param description a brief comment describing the metric represented by the counter - */ - public SnippetCounter(Group group, String name, String description) { - this.group = group; - this.name = name; - this.description = description; - if (group != null) { - List counters = group.counters; - this.index = counters.size(); - counters.add(this); - if (index == 0) { - groups.add(group); - } - } else { - this.index = -1; - } - } - - /** - * Increments the value of this counter. This method can be safely used in a snippet if it is - * invoked on a compile-time constant {@link SnippetCounter} object. - */ - public void inc() { - if (group != null) { - DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1); - } - } - - /** - * Gets the value of this counter. - */ - public long value() { - return value; - } - - /** - * Prints all the counter groups to a given stream. - */ - public static void printGroups(PrintStream out) { - for (Group group : groups) { - out.println(group); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.util.*; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; - -/** - * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a - * snippet. - * - * The frame states of side-effecting nodes are replaced with - * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid - * frame states are also assigned an invalid frame state. - * - * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. - */ -public class SnippetFrameStateCleanupPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); - } - - private static class CleanupState { - - public boolean containsFrameState; - - public CleanupState(boolean containsFrameState) { - this.containsFrameState = containsFrameState; - } - } - - /** - * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid - * frame states, so that they can be marked with an invalid frame state. - */ - private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure { - - @Override - protected void processNode(FixedNode node, CleanupState currentState) { - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (frameState != null) { - if (stateSplit.hasSideEffect()) { - currentState.containsFrameState = true; - stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); - } else { - stateSplit.setStateAfter(null); - } - if (frameState.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(frameState); - } - } - } - } - - @Override - protected CleanupState merge(MergeNode merge, List states) { - for (CleanupState state : states) { - if (state.containsFrameState) { - return new CleanupState(true); - } - } - return new CleanupState(false); - } - - @Override - protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { - return new CleanupState(oldState.containsFrameState); - } - - @Override - protected Map processLoop(LoopBeginNode loop, CleanupState initialState) { - LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); - boolean containsFrameState = false; - for (CleanupState state : info.endStates.values()) { - containsFrameState |= state.containsFrameState; - } - if (containsFrameState) { - loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); - } - if (containsFrameState || initialState.containsFrameState) { - for (CleanupState state : info.exitStates.values()) { - state.containsFrameState = true; - } - } - return info.exitStates; - } - - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,752 +0,0 @@ -/* - * Copyright (c) 2012, 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 java.lang.reflect.*; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.loop.*; -import com.oracle.graal.nodes.*; -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.common.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; -import com.oracle.graal.word.phases.*; - -/** - * A snippet template is a graph created by parsing a snippet method and then specialized by binding - * constants to the snippet's {@link ConstantParameter} parameters. - * - * Snippet templates can be managed in a {@link Cache}. - */ -public class SnippetTemplate { - - /** - * A snippet template key encapsulates the method from which a snippet was built and the - * arguments used to specialize the snippet. - * - * @see Cache - */ - public static class Key implements Iterable> { - - public final ResolvedJavaMethod method; - private final HashMap map = new HashMap<>(); - private int hash; - - public Key(ResolvedJavaMethod method) { - this.method = method; - this.hash = method.hashCode(); - } - - public Key add(String name, Object value) { - assert !map.containsKey(name); - map.put(name, value); - hash = hash ^ name.hashCode(); - if (value != null) { - hash *= (value.hashCode() + 1); - } - return this; - } - - public int length() { - return map.size(); - } - - public Object get(String name) { - return map.get(name); - } - - @Override - public Iterator> iterator() { - return map.entrySet().iterator(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Key) { - Key other = (Key) obj; - return other.method == method && other.map.equals(map); - } - return false; - } - - @Override - public int hashCode() { - return hash; - } - - @Override - public String toString() { - return MetaUtil.format("%h.%n", method) + map.toString(); - } - - public Set names() { - return map.keySet(); - } - } - - /** - * Arguments used to instantiate a template. - */ - public static class Arguments implements Iterable> { - - private final HashMap map = new HashMap<>(); - - public static Arguments arguments(String name, Object value) { - return new Arguments().add(name, value); - } - - public Arguments add(String name, Object value) { - assert !map.containsKey(name); - map.put(name, value); - return this; - } - - public int length() { - return map.size(); - } - - @Override - public Iterator> iterator() { - return map.entrySet().iterator(); - } - - @Override - public String toString() { - return map.toString(); - } - } - - /** - * A collection of snippet templates accessed by a {@link Key} instance. - */ - public static class Cache { - - private final ConcurrentHashMap templates = new ConcurrentHashMap<>(); - private final MetaAccessProvider runtime; - private final TargetDescription target; - - public Cache(MetaAccessProvider runtime, TargetDescription target) { - this.runtime = runtime; - this.target = target; - } - - /** - * Gets a template for a given key, creating it first if necessary. - */ - public SnippetTemplate get(final SnippetTemplate.Key key, final Assumptions assumptions) { - SnippetTemplate template = templates.get(key); - if (template == null) { - template = Debug.scope("SnippetSpecialization", key.method, new Callable() { - - @Override - public SnippetTemplate call() throws Exception { - return new SnippetTemplate(runtime, assumptions, target, key); - } - }); - // System.out.println(key + " -> " + template); - templates.put(key, template); - } - return template; - } - } - - public abstract static class AbstractTemplates { - - protected final Cache cache; - protected final MetaAccessProvider runtime; - protected final Assumptions assumptions; - protected Class snippetsClass; - - public AbstractTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { - this.runtime = runtime; - this.assumptions = assumptions; - if (snippetsClass == null) { - assert this instanceof Snippets; - this.snippetsClass = getClass(); - } else { - this.snippetsClass = snippetsClass; - } - this.cache = new Cache(runtime, target); - } - - protected ResolvedJavaMethod snippet(String name, Class... parameterTypes) { - try { - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(snippetsClass.getDeclaredMethod(name, parameterTypes)); - assert snippet.getAnnotation(Snippet.class) != null : "snippet is not annotated with @" + Snippet.class.getSimpleName(); - return snippet; - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } - } - } - - private static final Object UNUSED_PARAMETER = "DEAD PARAMETER"; - - /** - * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. - */ - public static boolean hasConstantParameter(ResolvedJavaMethod method) { - for (ConstantParameter p : MetaUtil.getParameterAnnotations(ConstantParameter.class, method)) { - if (p != null) { - return true; - } - } - return false; - } - - /** - * Creates a snippet template. - */ - public SnippetTemplate(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, SnippetTemplate.Key key) { - ResolvedJavaMethod method = key.method; - assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + method; - Signature signature = method.getSignature(); - - // Copy snippet graph, replacing constant parameters with given arguments - StructuredGraph snippetGraph = (StructuredGraph) method.getCompilerStorage().get(Graph.class); - StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); - IdentityHashMap replacements = new IdentityHashMap<>(); - replacements.put(snippetGraph.start(), snippetCopy.start()); - - int parameterCount = signature.getParameterCount(false); - assert checkTemplate(runtime, key, parameterCount, method, signature); - - Parameter[] parameterAnnotations = new Parameter[parameterCount]; - VarargsParameter[] varargsParameterAnnotations = new VarargsParameter[parameterCount]; - ConstantNode[] placeholders = new ConstantNode[parameterCount]; - for (int i = 0; i < parameterCount; i++) { - ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); - if (c != null) { - String name = c.value(); - Object arg = key.get(name); - Kind kind = signature.getParameterKind(i); - Constant constantArg; - if (arg instanceof Constant) { - constantArg = (Constant) arg; - } else { - constantArg = Constant.forBoxed(kind, arg); - } - replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); - } else { - VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); - if (vp != null) { - String name = vp.value(); - Varargs varargs = (Varargs) key.get(name); - Object array = varargs.getArray(); - ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); - replacements.put(snippetGraph.getLocal(i), placeholder); - placeholders[i] = placeholder; - varargsParameterAnnotations[i] = vp; - } else { - parameterAnnotations[i] = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - } - } - } - snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); - - Debug.dump(snippetCopy, "Before specialization"); - if (!replacements.isEmpty()) { - // Do deferred intrinsification of node intrinsics - new NodeIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); - new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); - - new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy); - } - assert NodeIntrinsificationVerificationPhase.verify(snippetCopy); - - // Gather the template parameters - parameters = new HashMap<>(); - for (int i = 0; i < parameterCount; i++) { - VarargsParameter vp = varargsParameterAnnotations[i]; - if (vp != null) { - assert snippetCopy.getLocal(i) == null; - Varargs varargs = (Varargs) key.get(vp.value()); - Object array = varargs.getArray(); - int length = Array.getLength(array); - LocalNode[] locals = new LocalNode[length]; - Stamp stamp = varargs.getArgStamp(); - for (int j = 0; j < length; j++) { - assert (parameterCount & 0xFFFF) == parameterCount; - int idx = i << 16 | j; - LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); - locals[j] = local; - } - parameters.put(vp.value(), locals); - - ConstantNode placeholder = placeholders[i]; - assert placeholder != null; - for (Node usage : placeholder.usages().snapshot()) { - if (usage instanceof LoadIndexedNode) { - LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; - Debug.dump(snippetCopy, "Before replacing %s", loadIndexed); - LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(locals, loadIndexed.index(), loadIndexed.stamp())); - snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); - Debug.dump(snippetCopy, "After replacing %s", loadIndexed); - } - } - } else { - Parameter p = parameterAnnotations[i]; - if (p != null) { - LocalNode local = snippetCopy.getLocal(i); - if (local == null) { - // Parameter value was eliminated - parameters.put(p.value(), UNUSED_PARAMETER); - } else { - parameters.put(p.value(), local); - } - } - } - } - - // Do any required loop explosion - boolean exploded = false; - do { - exploded = false; - ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first(); - if (explodeLoop != null) { // Earlier canonicalization may have removed the loop - // altogether - LoopBeginNode loopBegin = explodeLoop.findLoopBegin(); - if (loopBegin != null) { - LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); - int mark = snippetCopy.getMark(); - LoopTransformations.fullUnroll(loop, runtime, null); - new CanonicalizerPhase(runtime, assumptions, mark, null).apply(snippetCopy); - } - FixedNode explodeLoopNext = explodeLoop.next(); - explodeLoop.clearSuccessors(); - explodeLoop.replaceAtPredecessor(explodeLoopNext); - explodeLoop.replaceAtUsages(null); - GraphUtil.killCFG(explodeLoop); - exploded = true; - } - } while (exploded); - - // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free - // of side-effects that prevent deoptimizing to a point before the snippet). - ArrayList curSideEffectNodes = new ArrayList<>(); - ArrayList curStampNodes = new ArrayList<>(); - for (Node node : snippetCopy.getNodes()) { - if (node instanceof ValueNode && ((ValueNode) node).stamp() == StampFactory.forNodeIntrinsic()) { - curStampNodes.add((ValueNode) node); - } - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (stateSplit.hasSideEffect()) { - curSideEffectNodes.add((StateSplit) node); - } - if (frameState != null) { - stateSplit.setStateAfter(null); - } - } - } - - new DeadCodeEliminationPhase().apply(snippetCopy); - - assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); - - this.snippet = snippetCopy; - ReturnNode retNode = null; - StartNode entryPointNode = snippet.start(); - - new DeadCodeEliminationPhase().apply(snippetCopy); - - nodes = new ArrayList<>(snippet.getNodeCount()); - for (Node node : snippet.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - retNode = (ReturnNode) node; - } - } - } - - this.sideEffectNodes = curSideEffectNodes; - this.stampNodes = curStampNodes; - this.returnNode = retNode; - } - - private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) { - for (int i = 0; i < parameterCount; i++) { - if (placeholders[i] != null) { - assert placeholders[i].isDeleted() : placeholders[i]; - } - } - return true; - } - - private static boolean checkConstantArgument(MetaAccessProvider runtime, final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) { - ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()); - if (runtime.lookupJavaType(WordBase.class).isAssignableFrom(type)) { - assert arg instanceof Constant : method + ": word constant parameters must be passed boxed in a Constant value: " + arg; - return true; - } - if (kind == Kind.Object) { - assert arg == null || type.isInstance(Constant.forObject(arg)) : method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName(); - } else { - assert arg != null && kind.toBoxedJavaClass() == arg.getClass() : method + ": wrong value kind for " + name + ": expected " + kind + ", got " + - (arg == null ? "null" : arg.getClass().getSimpleName()); - } - return true; - } - - private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { - Object arg = varargs.getArray(); - ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass()); - assert type.isArray() : "varargs parameter must be an array type"; - assert type.isInstance(Constant.forObject(arg)) : "value for " + name + " is not a " + MetaUtil.toJavaName(type) + " instance: " + arg; - return true; - } - - /** - * The graph built from the snippet method. - */ - private final StructuredGraph snippet; - - /** - * The named parameters of this template that must be bound to values during instantiation. For - * a parameter that is still live after specialization, the value in this map is either a - * {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter, the - * value is identical to the key. - */ - private final Map parameters; - - /** - * The return node (if any) of the snippet. - */ - private final ReturnNode returnNode; - - /** - * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during - * instantiation. - */ - private final ArrayList sideEffectNodes; - - /** - * The nodes that inherit the {@link ValueNode#stamp()} from the replacee during instantiation. - */ - private final ArrayList stampNodes; - - /** - * The nodes to be inlined when this specialization is instantiated. - */ - private final ArrayList nodes; - - /** - * Gets the instantiation-time bindings to this template's parameters. - * - * @return the map that will be used to bind arguments to parameters when inlining this template - */ - private IdentityHashMap bind(StructuredGraph replaceeGraph, MetaAccessProvider runtime, SnippetTemplate.Arguments args) { - IdentityHashMap replacements = new IdentityHashMap<>(); - assert args.length() == parameters.size() : "number of args (" + args.length() + ") != number of parameters (" + parameters.size() + ")"; - for (Map.Entry e : args) { - String name = e.getKey(); - Object parameter = parameters.get(name); - assert parameter != null : this + " has no parameter named " + name; - Object argument = e.getValue(); - if (parameter instanceof LocalNode) { - if (argument instanceof ValueNode) { - replacements.put((LocalNode) parameter, (ValueNode) argument); - } else { - Kind kind = ((LocalNode) parameter).kind(); - assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + name; - Constant constant = Constant.forBoxed(kind, argument); - replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); - } - } else if (parameter instanceof LocalNode[]) { - LocalNode[] locals = (LocalNode[]) parameter; - int length = locals.length; - List list = null; - Object array = null; - if (argument instanceof List) { - list = (List) argument; - assert list.size() == length : length + " != " + list.size(); - } else { - array = argument; - assert array != null && array.getClass().isArray(); - assert Array.getLength(array) == length : length + " != " + Array.getLength(array); - } - - for (int j = 0; j < length; j++) { - LocalNode local = locals[j]; - assert local != null; - Object value = list != null ? list.get(j) : Array.get(array, j); - if (value instanceof ValueNode) { - replacements.put(local, (ValueNode) value); - } else { - Constant constant = Constant.forBoxed(local.kind(), value); - ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); - replacements.put(local, element); - } - } - } else { - assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter; - } - } - return replacements; - } - - /** - * Logic for replacing a snippet-lowered node at its usages with the return value of the - * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default} - * replacement logic can be used to handle mismatches between the stamp of the node being - * lowered and the stamp of the snippet's return value. - */ - public interface UsageReplacer { - - /** - * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}. - */ - void replace(ValueNode oldNode, ValueNode newNode); - } - - /** - * Represents the default {@link UsageReplacer usage replacer} logic which simply delegates to - * {@link Node#replaceAtUsages(Node)}. - */ - public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() { - - @Override - public void replace(ValueNode oldNode, ValueNode newNode) { - oldNode.replaceAtUsages(newNode); - } - }; - - /** - * Replaces a given fixed node with this specialized snippet. - * - * @param runtime - * @param replacee the node that will be replaced - * @param replacer object that replaces the usages of {@code replacee} - * @param args the arguments to be bound to the flattened positional parameters of the snippet - * @return the map of duplicated nodes (original -> duplicate) - */ - public Map instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { - - // Inline the snippet nodes, replacing parameters with the given args in the process - String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; - StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); - StartNode entryPointNode = snippet.start(); - FixedNode firstCFGNode = entryPointNode.next(); - StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); - IdentityHashMap replacements = bind(replaceeGraph, runtime, args); - Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); - Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); - - // Re-wire the control flow graph around the replacee - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - replacee.replaceAtPredecessor(firstCFGNodeDuplicate); - FixedNode next = null; - if (replacee instanceof FixedWithNextNode) { - FixedWithNextNode fwn = (FixedWithNextNode) replacee; - next = fwn.next(); - fwn.setNext(null); - } - - if (replacee instanceof StateSplit) { - for (StateSplit sideEffectNode : sideEffectNodes) { - assert ((StateSplit) replacee).hasSideEffect(); - Node sideEffectDup = duplicates.get(sideEffectNode); - ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); - } - } - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); - } - - // Replace all usages of the replacee with the value returned by the snippet - ValueNode returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof LocalNode) { - returnValue = (ValueNode) replacements.get(returnNode.result()); - } else { - returnValue = (ValueNode) duplicates.get(returnNode.result()); - } - assert returnValue != null || replacee.usages().isEmpty(); - replacer.replace(replacee, returnValue); - - Node returnDuplicate = duplicates.get(returnNode); - if (returnDuplicate.isAlive()) { - returnDuplicate.clearInputs(); - returnDuplicate.replaceAndDelete(next); - } - } - - // Remove the replacee from its graph - replacee.clearInputs(); - replacee.replaceAtUsages(null); - GraphUtil.killCFG(replacee); - - Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); - return duplicates; - } - - /** - * Gets a copy of the specialized graph. - */ - public StructuredGraph copySpecializedGraph() { - return snippet.copy(); - } - - /** - * Replaces a given floating node with this specialized snippet. - * - * @param runtime - * @param replacee the node that will be replaced - * @param replacer object that replaces the usages of {@code replacee} - * @param args the arguments to be bound to the flattened positional parameters of the snippet - */ - public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) { - - // Inline the snippet nodes, replacing parameters with the given args in the process - String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; - StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); - StartNode entryPointNode = snippet.start(); - FixedNode firstCFGNode = entryPointNode.next(); - StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); - IdentityHashMap replacements = bind(replaceeGraph, runtime, args); - Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); - Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); - - FixedWithNextNode lastFixedNode = tool.lastFixedNode(); - assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph; - FixedNode next = lastFixedNode.next(); - lastFixedNode.setNext(null); - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate); - - if (replacee instanceof StateSplit) { - for (StateSplit sideEffectNode : sideEffectNodes) { - assert ((StateSplit) replacee).hasSideEffect(); - Node sideEffectDup = duplicates.get(sideEffectNode); - ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); - } - } - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); - } - - // Replace all usages of the replacee with the value returned by the snippet - assert returnNode != null : replaceeGraph; - ValueNode returnValue = null; - if (returnNode.result() instanceof LocalNode) { - returnValue = (ValueNode) replacements.get(returnNode.result()); - } else { - returnValue = (ValueNode) duplicates.get(returnNode.result()); - } - assert returnValue != null || replacee.usages().isEmpty(); - replacer.replace(replacee, returnValue); - - tool.setLastFixedNode(null); - Node returnDuplicate = duplicates.get(returnNode); - if (returnDuplicate.isAlive()) { - returnDuplicate.clearInputs(); - returnDuplicate.replaceAndDelete(next); - if (next != null && next.predecessor() instanceof FixedWithNextNode) { - tool.setLastFixedNode((FixedWithNextNode) next.predecessor()); - } - } - - Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(snippet.toString()).append('('); - String sep = ""; - for (Map.Entry e : parameters.entrySet()) { - String name = e.getKey(); - Object value = e.getValue(); - buf.append(sep); - sep = ", "; - if (value == UNUSED_PARAMETER) { - buf.append(" ").append(name); - } else if (value instanceof LocalNode) { - LocalNode local = (LocalNode) value; - buf.append(local.kind().getJavaName()).append(' ').append(name); - } else { - LocalNode[] locals = (LocalNode[]) value; - String kind = locals.length == 0 ? "?" : locals[0].kind().getJavaName(); - buf.append(kind).append('[').append(locals.length).append("] ").append(name); - } - } - return buf.append(')').toString(); - } - - private static boolean checkTemplate(MetaAccessProvider runtime, SnippetTemplate.Key key, int parameterCount, ResolvedJavaMethod method, Signature signature) { - Set expected = new HashSet<>(); - for (int i = 0; i < parameterCount; i++) { - ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); - VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); - Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - if (c != null) { - assert vp == null && p == null; - String name = c.value(); - expected.add(name); - Kind kind = signature.getParameterKind(i); - assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; - assert checkConstantArgument(runtime, method, signature, i, c.value(), key.get(name), kind); - } else if (vp != null) { - assert p == null; - String name = vp.value(); - expected.add(name); - assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; - assert key.get(name) instanceof Varargs; - Varargs varargs = (Varargs) key.get(name); - assert checkVarargs(method, signature, i, name, varargs); - } else { - assert p != null : method + ": parameter " + i + " must be annotated with exactly one of " + "@" + ConstantParameter.class.getSimpleName() + " or " + "@" + - VarargsParameter.class.getSimpleName() + " or " + "@" + Parameter.class.getSimpleName(); - } - } - if (!key.names().containsAll(expected)) { - expected.removeAll(key.names()); - assert false : expected + " missing from key " + key; - } - if (!expected.containsAll(key.names())) { - Set namesCopy = new HashSet<>(key.names()); - namesCopy.removeAll(expected); - assert false : "parameter(s) " + namesCopy + " should be annotated with @" + ConstantParameter.class.getSimpleName() + " or @" + VarargsParameter.class.getSimpleName() + " in " + - MetaUtil.format("%H.%n(%p)", method); - } - return true; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/Snippets.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/Snippets.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011, 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; - -/** - * Marker interface for a class that defines one or more {@link Snippet}s. - */ -public interface Snippets { -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/UnsafeSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/UnsafeSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,383 +0,0 @@ -/* - * Copyright (c) 2011, 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.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.replacements.ClassSubstitution.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Substitutions for {@link sun.misc.Unsafe} methods. - */ -@ClassSubstitution(sun.misc.Unsafe.class) -public class UnsafeSubstitutions { - - @MethodSubstitution(isStatic = false) - public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) { - return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); - } - - @MethodSubstitution(isStatic = false) - public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) { - return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); - } - - @MethodSubstitution(isStatic = false) - public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) { - return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); - } - - @MethodSubstitution(isStatic = false) - public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - return UnsafeLoadNode.load(o, 0, offset, Kind.Object); - } - - @MethodSubstitution(isStatic = false) - public static Object getObjectVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - Object result = getObject(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Object); - } - - @MethodSubstitution(isStatic = false) - public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putObject(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putObject(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - Integer value = UnsafeLoadNode.load(o, 0, offset, Kind.Int); - return value; - } - - @MethodSubstitution(isStatic = false) - public static int getIntVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - int result = getInt(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Int); - } - - @MethodSubstitution(isStatic = false) - public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putInt(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putInt(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Boolean result = UnsafeLoadNode.load(o, 0, offset, Kind.Boolean); - return result; - } - - @MethodSubstitution(isStatic = false) - public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - boolean result = getBoolean(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Boolean); - } - - @MethodSubstitution(isStatic = false) - public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putBoolean(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Byte result = UnsafeLoadNode.load(o, 0, offset, Kind.Byte); - return result; - } - - @MethodSubstitution(isStatic = false) - public static byte getByteVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - byte result = getByte(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Byte); - } - - @MethodSubstitution(isStatic = false) - public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putByte(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Short result = UnsafeLoadNode.load(o, 0, offset, Kind.Short); - return result; - } - - @MethodSubstitution(isStatic = false) - public static short getShortVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - short result = getShort(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Short); - } - - @MethodSubstitution(isStatic = false) - public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putShort(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Character result = UnsafeLoadNode.load(o, 0, offset, Kind.Char); - return result; - } - - @MethodSubstitution(isStatic = false) - public static char getCharVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - char result = getChar(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Char); - } - - @MethodSubstitution(isStatic = false) - public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putChar(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Long result = UnsafeLoadNode.load(o, 0, offset, Kind.Long); - return result; - } - - @MethodSubstitution(isStatic = false) - public static long getLongVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - long result = getLong(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Long); - } - - @MethodSubstitution(isStatic = false) - public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putLong(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putLong(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Float result = UnsafeLoadNode.load(o, 0, offset, Kind.Float); - return result; - } - - @MethodSubstitution(isStatic = false) - public static float getFloatVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - float result = getFloat(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Float); - } - - @MethodSubstitution(isStatic = false) - public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putFloat(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Double result = UnsafeLoadNode.load(o, 0, offset, Kind.Double); - return result; - } - - @MethodSubstitution(isStatic = false) - public static double getDoubleVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - double result = getDouble(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Double); - } - - @MethodSubstitution(isStatic = false) - public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putDouble(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) { - DirectStoreNode.store(address, value, Kind.Byte); - } - - @MethodSubstitution(isStatic = false) - public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) { - DirectStoreNode.store(address, value, Kind.Short); - } - - @MethodSubstitution(isStatic = false) - public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) { - DirectStoreNode.store(address, value, Kind.Char); - } - - @MethodSubstitution(isStatic = false) - public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) { - DirectStoreNode.store(address, value, Kind.Int); - } - - @MethodSubstitution(isStatic = false) - public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) { - DirectStoreNode.store(address, value, Kind.Long); - } - - @MethodSubstitution(isStatic = false) - public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) { - DirectStoreNode.store(address, value, Kind.Float); - } - - @MethodSubstitution(isStatic = false) - public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) { - DirectStoreNode.store(address, value, Kind.Double); - } - - @MethodSubstitution(isStatic = false) - public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Byte); - } - - @MethodSubstitution(isStatic = false) - public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Short); - } - - @MethodSubstitution(isStatic = false) - public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Char); - } - - @MethodSubstitution(isStatic = false) - public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Int); - } - - @MethodSubstitution(isStatic = false) - public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Long); - } - - @MethodSubstitution(isStatic = false) - public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Float); - } - - @MethodSubstitution(isStatic = false) - public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Double); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2011, 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 static com.oracle.graal.nodes.calc.ConditionalNode.*; -import static com.oracle.graal.nodes.calc.Condition.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.replacements.ClassSubstitution.*; - -/** - * Substitutions for {@link UnsignedMath}. - */ -@ClassSubstitution(UnsignedMath.class) -public class UnsignedMathSubstitutions { - - @MethodSubstitution - public static boolean aboveThan(int a, int b) { - return materializeCondition(BT, b, a); - } - - @MethodSubstitution - public static boolean aboveOrEqual(int a, int b) { - return !materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowThan for two numbers. - */ - @MethodSubstitution - public static boolean belowThan(int a, int b) { - return materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowOrEqual for two numbers. - */ - @MethodSubstitution - public static boolean belowOrEqual(int a, int b) { - return !materializeCondition(BT, b, a); - } - - /** - * Unsigned comparison aboveThan for two numbers. - */ - @MethodSubstitution - public static boolean aboveThan(long a, long b) { - return materializeCondition(BT, b, a); - } - - /** - * Unsigned comparison aboveOrEqual for two numbers. - */ - @MethodSubstitution - public static boolean aboveOrEqual(long a, long b) { - return !materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowThan for two numbers. - */ - @MethodSubstitution - public static boolean belowThan(long a, long b) { - return materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowOrEqual for two numbers. - */ - @MethodSubstitution - public static boolean belowOrEqual(long a, long b) { - return !materializeCondition(BT, b, a); - } - - /** - * Unsigned division for two numbers. - */ - @MethodSubstitution - public static int divide(int a, int b) { - return unsignedDivide(Kind.Int, a, b); - } - - /** - * Unsigned remainder for two numbers. - */ - @MethodSubstitution - public static int remainder(int a, int b) { - return unsignedRemainder(Kind.Int, a, b); - } - - /** - * Unsigned division for two numbers. - */ - @MethodSubstitution - public static long divide(long a, long b) { - return unsignedDivide(Kind.Long, a, b); - } - - /** - * Unsigned remainder for two numbers. - */ - @MethodSubstitution - public static long remainder(long a, long b) { - return unsignedRemainder(Kind.Long, a, b); - } - - @NodeIntrinsic(UnsignedDivNode.class) - private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b); - - @NodeIntrinsic(UnsignedDivNode.class) - private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b); - - @NodeIntrinsic(UnsignedRemNode.class) - private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b); - - @NodeIntrinsic(UnsignedRemNode.class) - private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b); -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BitCountNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BitCountNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public BitCountNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.bitCount((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(Long.bitCount(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int bitCount(int v); - - @NodeIntrinsic - public static native int bitCount(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Int); - gen.emitBitCount(result, gen.operand(value)); - gen.setResult(this, result); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public BitScanForwardNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.numberOfTrailingZeros((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(Long.numberOfTrailingZeros(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int scan(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Int); - gen.emitBitScanForward(result, gen.operand(value)); - gen.setResult(this, result); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public BitScanReverseNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int scan(int v); - - @NodeIntrinsic - public static native int scan(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Int); - gen.emitBitScanReverse(result, gen.operand(value)); - gen.setResult(this, result); - } - -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -/** - * Instances of this node class will look for a preceding if node and put the given probability into - * the if node's taken probability. Then the branch probability node will be removed. This node is - * intended primarily for snippets, so that they can define their fast and slow paths. - */ -public class BranchProbabilityNode extends FixedWithNextNode implements Simplifiable { - - public static final double LIKELY_PROBABILITY = 0.6; - public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY; - - public static final double FREQUENT_PROBABILITY = 0.9; - public static final double NOT_FREQUENT_PROBABILITY = 1 - FREQUENT_PROBABILITY; - - public static final double FAST_PATH_PROBABILITY = 0.99; - public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY; - - public static final double NOT_DEOPT_PATH_PROBABILITY = 0.999; - public static final double DEOPT_PATH_PROBABILITY = 1 - NOT_DEOPT_PATH_PROBABILITY; - - private final double probability; - - public BranchProbabilityNode(double probability) { - super(StampFactory.forVoid()); - assert probability >= 0 && probability <= 1; - this.probability = probability; - } - - @Override - public void simplify(SimplifierTool tool) { - FixedNode current = this; - while (!(current instanceof BeginNode)) { - current = (FixedNode) current.predecessor(); - } - BeginNode begin = (BeginNode) current; - assert begin.predecessor() instanceof IfNode : "explicit branch probability cannot follow a merge, only if nodes"; - IfNode ifNode = (IfNode) begin.predecessor(); - if (ifNode.trueSuccessor() == begin) { - ifNode.setTrueSuccessorProbability(probability); - } else { - ifNode.setTrueSuccessorProbability(1 - probability); - } - - FixedNode next = next(); - setNext(null); - ((FixedWithNextNode) predecessor()).setNext(next); - GraphUtil.killCFG(this); - } - - @NodeIntrinsic - public static native void probability(@ConstantNodeParameter double probability); - -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 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.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a - * {@link StateSplit} and does not include a write barrier. - */ -public class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable { - - @Input private ValueNode object; - @Input private ValueNode value; - @Input private ValueNode offset; - private final int displacement; - - public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) { - super(StampFactory.forVoid()); - this.object = object; - this.value = value; - this.offset = offset; - this.displacement = displacement; - } - - @NodeIntrinsic - public static native void storeObject(Object obj, @ConstantNodeParameter int displacement, long offset, Object value); - - @NodeIntrinsic - public static native void storeLong(Object obj, @ConstantNodeParameter int displacement, long offset, long value); - - @NodeIntrinsic - public static native void storeWord(Object obj, @ConstantNodeParameter int displacement, long offset, Word value); - - @NodeIntrinsic - public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value); - - @Override - public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) this.graph(); - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); - WriteNode write = graph.add(new WriteNode(object, value, location)); - graph.replaceFixedWithFixed(this, write); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/DirectReadNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012, 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.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a - * {@link StateSplit} and takes a computed address instead of an object. - */ -public class DirectReadNode extends FixedWithNextNode implements LIRLowerable { - - @Input private ValueNode address; - private final Kind readKind; - - public DirectReadNode(ValueNode address, Kind readKind) { - super(StampFactory.forKind(readKind)); - this.address = address; - this.readKind = readKind; - } - - @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); - } - - @NodeIntrinsic - public static native T read(long address, @ConstantNodeParameter Kind kind); -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2012, 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.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a - * {@link StateSplit} and takes a computed address instead of an object. - */ -public class DirectStoreNode extends FixedWithNextNode implements LIRLowerable { - - @Input private ValueNode address; - @Input private ValueNode value; - private final Kind kind; - - public DirectStoreNode(ValueNode address, ValueNode value, Kind kind) { - super(StampFactory.forVoid()); - this.address = address; - this.value = value; - this.kind = kind; - } - - @Override - public void generate(LIRGeneratorTool gen) { - Value v = gen.operand(value); - gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); - } - - /* - * The kind of the store is provided explicitly in these intrinsics because it is not always - * possible to determine the kind from the given value during compilation (because stack kinds - * are used). - */ - - @NodeIntrinsic - public static native void store(long address, boolean value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, byte value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, short value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, char value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, int value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, long value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, float value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, double value, @ConstantNodeParameter Kind kind); -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2012, 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 java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.replacements.Snippet.*; - -/** - * Placeholder node to denote to snippet preparation that the following loop must be completely - * unrolled. - * - * @see VarargsParameter - */ -public final class ExplodeLoopNode extends FixedWithNextNode { - - public ExplodeLoopNode() { - super(StampFactory.forVoid()); - } - - public LoopBeginNode findLoopBegin() { - Node next = next(); - ArrayList succs = new ArrayList<>(); - while (!(next instanceof LoopBeginNode)) { - assert next != null : "cannot find loop after " + this; - for (Node n : next.cfgSuccessors()) { - succs.add(n); - } - if (succs.size() == 1) { - next = succs.get(0); - } else { - return null; - } - } - return (LoopBeginNode) next; - } - - /** - * A call to this method must be placed immediately prior to the loop that is to be exploded. - */ - @NodeIntrinsic - public static native void explodeLoop(); -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2009, 2011, 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.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.replacements.Snippet.*; - -/** - * Implements the semantics of {@link VarargsParameter}. - */ -public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable { - - @Input private ValueNode index; - - private final LocalNode[] locals; - - public LoadSnippetVarargParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) { - super(stamp); - this.index = index; - this.locals = locals; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (index.isConstant()) { - return locals[index.asConstant().asInt()]; - } - return this; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013, 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 java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.phases.common.*; - -public class MacroNode extends AbstractStateSplit implements Lowerable { - - @Input protected final NodeInputList arguments; - - private final int bci; - private final ResolvedJavaMethod targetMethod; - private final JavaType returnType; - - protected MacroNode(Invoke invoke) { - super(invoke.node().stamp(), invoke.stateAfter()); - this.arguments = new NodeInputList<>(this, invoke.methodCallTarget().arguments()); - this.bci = invoke.bci(); - this.targetMethod = invoke.methodCallTarget().targetMethod(); - this.returnType = invoke.methodCallTarget().returnType(); - } - - public int getBci() { - return bci; - } - - public ResolvedJavaMethod getTargetMethod() { - return targetMethod; - } - - @SuppressWarnings("unused") - protected StructuredGraph getSnippetGraph(LoweringTool tool) { - return null; - } - - @Override - public void lower(LoweringTool tool) { - StructuredGraph snippetGraph = getSnippetGraph(tool); - - InvokeNode invoke = replaceWithInvoke(); - - if (snippetGraph != null) { - InliningUtil.inline(invoke, snippetGraph, false); - } - } - - private InvokeNode replaceWithInvoke() { - InvokeNode invoke = createInvoke(); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); - return invoke; - } - - protected InvokeNode createInvoke() { - InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special; - MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnType)); - InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); - invoke.setStateAfter(stateAfter()); - return invoke; - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2012, 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.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, LIRGenLowerable { - - @Input private ValueNode x; - private final Operation operation; - - public enum Operation { - ABS, SQRT, LOG, LOG10, SIN, COS, TAN - } - - public ValueNode x() { - return x; - } - - public Operation operation() { - return operation; - } - - public MathIntrinsicNode(ValueNode x, Operation op) { - super(StampFactory.forKind(x.kind())); - assert x.kind() == Kind.Double; - this.x = x; - this.operation = op; - } - - @Override - public void generate(LIRGenerator gen) { - Variable input = gen.load(gen.operand(x())); - Variable result = gen.newVariable(kind()); - switch (operation()) { - case ABS: - gen.emitMathAbs(result, input); - break; - case SQRT: - gen.emitMathSqrt(result, input); - break; - case LOG: - gen.emitMathLog(result, input, false); - break; - case LOG10: - gen.emitMathLog(result, input, true); - break; - case SIN: - gen.emitMathSin(result, input); - break; - case COS: - gen.emitMathCos(result, input); - break; - case TAN: - gen.emitMathTan(result, input); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - gen.setResult(this, result); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (x().isConstant()) { - double value = x().asConstant().asDouble(); - switch (operation()) { - case ABS: - return ConstantNode.forDouble(Math.abs(value), graph()); - case SQRT: - return ConstantNode.forDouble(Math.sqrt(value), graph()); - case LOG: - return ConstantNode.forDouble(Math.log(value), graph()); - case LOG10: - return ConstantNode.forDouble(Math.log10(value), graph()); - case SIN: - return ConstantNode.forDouble(Math.sin(value), graph()); - case COS: - return ConstantNode.forDouble(Math.cos(value), graph()); - case TAN: - return ConstantNode.forDouble(Math.tan(value), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native double compute(double x, @ConstantNodeParameter Operation op); -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Access the value of a specific register. - */ -@NodeInfo(nameTemplate = "ReadRegister %{p#register}") -public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable { - - /** - * The fixed register to access. - */ - private final Register register; - - /** - * When true, subsequent uses of this node use the fixed register; when false, the value is - * moved into a new virtual register so that the fixed register is not seen by uses. - */ - private final boolean directUse; - - /** - * When true, this node is also an implicit definition of the value for the register allocator, - * i.e., the register is an implicit incoming value; when false, the register must be defined in - * the same method or must be an register excluded from register allocation. - */ - private final boolean incoming; - - public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) { - super(StampFactory.forKind(kind)); - this.register = register; - this.directUse = directUse; - this.incoming = incoming; - } - - /** - * Constructor to be used by node intrinsics where the stamp is inferred from the intrinsic - * definition. - */ - public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { - super(StampFactory.forNodeIntrinsic()); - this.register = register; - this.directUse = directUse; - this.incoming = incoming; - } - - @Override - public void generate(LIRGenerator generator) { - Value result = register.asValue(kind()); - if (incoming) { - generator.emitIncomingValues(new Value[]{result}); - } - if (!directUse) { - result = generator.emitMove(result); - } - generator.setResult(this, result); - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "%" + register; - } else { - return super.toString(verbosity); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public ReverseBytesNode(ValueNode value) { - super(StampFactory.forKind(value.kind())); - assert kind().getStackKind() == Kind.Int || kind() == Kind.Long; - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.reverseBytes((int) v), graph()); - } else if (kind() == Kind.Long) { - return ConstantNode.forLong(Long.reverseBytes(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int reverse(int v); - - @NodeIntrinsic - public static native long reverse(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(value.kind()); - gen.emitByteSwap(result, gen.operand(value)); - gen.setResult(this, result); - } -} diff -r 2361bf148c06 -r 102b5249e97e graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Wed Mar 20 22:23:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013, 2013, 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.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * Changes the value of a specific register. - */ -@NodeInfo(nameTemplate = "WriteRegister %{p#register}") -public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable { - - /** - * The fixed register to access. - */ - private final Register register; - - /** - * The new value assigned to the register. - */ - @Input private ValueNode value; - - public WriteRegisterNode(Register register, ValueNode value) { - super(StampFactory.forVoid()); - this.register = register; - this.value = value; - } - - @Override - public void generate(LIRGeneratorTool generator) { - Value val = generator.operand(value); - generator.emitMove(val, register.asValue(val.getKind())); - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "%" + register; - } else { - return super.toString(verbosity); - } - } -} diff -r 2361bf148c06 -r 102b5249e97e make/build-graal.xml --- a/make/build-graal.xml Wed Mar 20 22:23:14 2013 +0100 +++ b/make/build-graal.xml Wed Mar 20 22:30:33 2013 +0100 @@ -48,7 +48,7 @@ - + @@ -56,7 +56,7 @@ - + diff -r 2361bf148c06 -r 102b5249e97e mx/projects --- a/mx/projects Wed Mar 20 22:23:14 2013 +0100 +++ b/mx/projects Wed Mar 20 22:30:33 2013 +0100 @@ -82,14 +82,14 @@ # graal.hotspot project@com.oracle.graal.hotspot@subDir=graal project@com.oracle.graal.hotspot@sourceDirs=src -project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.snippets,com.oracle.graal.api.runtime,com.oracle.graal.printer +project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.api.runtime,com.oracle.graal.printer project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot@javaCompliance=1.7 # graal.hotspot.amd64 project@com.oracle.graal.hotspot.amd64@subDir=graal project@com.oracle.graal.hotspot.amd64@sourceDirs=src -project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.amd64,com.oracle.graal.snippets.amd64 +project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.amd64,com.oracle.graal.replacements.amd64 project@com.oracle.graal.hotspot.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.amd64@javaCompliance=1.7 @@ -182,26 +182,26 @@ project@com.oracle.graal.word@checkstyle=com.oracle.graal.graph project@com.oracle.graal.word@javaCompliance=1.7 -# graal.snippets -project@com.oracle.graal.snippets@subDir=graal -project@com.oracle.graal.snippets@sourceDirs=src -project@com.oracle.graal.snippets@dependencies=com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.word -project@com.oracle.graal.snippets@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.snippets@javaCompliance=1.7 +# graal.replacements +project@com.oracle.graal.replacements@subDir=graal +project@com.oracle.graal.replacements@sourceDirs=src +project@com.oracle.graal.replacements@dependencies=com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.word +project@com.oracle.graal.replacements@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.replacements@javaCompliance=1.7 -# graal.snippets.amd64 -project@com.oracle.graal.snippets.amd64@subDir=graal -project@com.oracle.graal.snippets.amd64@sourceDirs=src -project@com.oracle.graal.snippets.amd64@dependencies=com.oracle.graal.snippets -project@com.oracle.graal.snippets.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.snippets.amd64@javaCompliance=1.7 +# graal.replacements.amd64 +project@com.oracle.graal.replacements.amd64@subDir=graal +project@com.oracle.graal.replacements.amd64@sourceDirs=src +project@com.oracle.graal.replacements.amd64@dependencies=com.oracle.graal.replacements +project@com.oracle.graal.replacements.amd64@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.replacements.amd64@javaCompliance=1.7 -# graal.snippets.test -project@com.oracle.graal.snippets.test@subDir=graal -project@com.oracle.graal.snippets.test@sourceDirs=src -project@com.oracle.graal.snippets.test@dependencies=com.oracle.graal.snippets,com.oracle.graal.compiler.test -project@com.oracle.graal.snippets.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.snippets.test@javaCompliance=1.7 +# graal.replacements.test +project@com.oracle.graal.replacements.test@subDir=graal +project@com.oracle.graal.replacements.test@sourceDirs=src +project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.replacements,com.oracle.graal.compiler.test +project@com.oracle.graal.replacements.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.replacements.test@javaCompliance=1.7 # graal.nodes project@com.oracle.graal.nodes@subDir=graal