changeset 17231:58f1d1335ef4

force inline Fields.getObject(Object, int, Class) so that a constant value bound to its last parameter is connected with the DeferredPiNode used in Fields.getObject(Object, long, Class)
author Doug Simon <doug.simon@oracle.com>
date Fri, 26 Sep 2014 14:53:23 +0200
parents 627b11398fdd
children be6f5fad74c6
files graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeferredPiNode.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FieldsSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java
diffstat 6 files changed, 238 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Sep 26 14:45:10 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Sep 26 14:53:23 2014 +0200
@@ -120,7 +120,13 @@
         return types[index];
     }
 
-    private boolean checkAssignable(int index, Object value) {
+    /**
+     * Checks that a given field is assignable from a given value.
+     *
+     * @param index the index of the field to check
+     * @param value a value that will be assigned to the field
+     */
+    private boolean checkAssignableFrom(int index, Object value) {
         assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("%s.%s of type %s is not assignable from %s", clazz.getSimpleName(), getName(index),
                         getType(index).getSimpleName(), value.getClass().getSimpleName());
         return true;
@@ -150,7 +156,7 @@
                 assert false : "unhandled property type: " + type;
             }
         } else {
-            assert checkAssignable(index, value);
+            assert checkAssignableFrom(index, value);
             unsafe.putObject(object, dataOffset, value);
         }
     }
@@ -211,10 +217,23 @@
      *
      * @param object the object whose field is to be read
      * @param index the index of the field (between 0 and {@link #getCount()})
+     * @return the value of the specified field cast to {@code c}
+     */
+    public Object getObject(Object object, int index) {
+        return getObject(object, offsets[index], Object.class);
+    }
+
+    /**
+     * Gets the value of an object field and casts it to a given type.
+     *
+     * NOTE: All callers of this method should use a class literal for the last argument.
+     *
+     * @param object the object whose field is to be read
+     * @param index the index of the field (between 0 and {@link #getCount()})
      * @param asType the type to which the returned object is cast
      * @return the value of the specified field cast to {@code c}
      */
-    public <T> T getObject(Object object, int index, Class<T> asType) {
+    protected <T> T getObject(Object object, int index, Class<T> asType) {
         return getObject(object, offsets[index], asType);
     }
 
@@ -230,12 +249,11 @@
      * @param value the value to be written to the field
      */
     protected void putObject(Object object, int index, Object value) {
-        assert checkAssignable(index, value);
+        assert checkAssignableFrom(index, value);
         putObject(object, offsets[index], value);
     }
 
     private static void putObject(Object object, long offset, Object value) {
         unsafe.putObject(object, offset, value);
     }
-
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Sep 26 14:45:10 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Sep 26 14:53:23 2014 +0200
@@ -284,7 +284,7 @@
      *
      * <pre>
      *     if (node.getNodeClass().is(BeginNode.class)) { ... }
-     *
+     * 
      *     // Due to generated Node classes, the test below
      *     // is *not* the same as the test above:
      *     if (node.getClass() == BeginNode.class) { ... }
@@ -471,7 +471,7 @@
                         assert false : "unhandled property type: " + type;
                     }
                 } else {
-                    Object o = properties.getObject(n, i, Object.class);
+                    Object o = properties.getObject(n, i);
                     number += deepHashCode0(o);
                 }
                 number *= 13;
@@ -566,8 +566,8 @@
                     assert false : "unhandled type: " + type;
                 }
             } else {
-                Object objectA = properties.getObject(a, i, Object.class);
-                Object objectB = properties.getObject(b, i, Object.class);
+                Object objectA = properties.getObject(a, i);
+                Object objectB = properties.getObject(b, i);
                 if (objectA != objectB) {
                     if (objectA != null && objectB != null) {
                         if (!deepEquals0(objectA, objectB)) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeferredPiNode.java	Fri Sep 26 14:45:10 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +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.nodes;
-
-//JaCoCo Exclude
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * A node that changes the type of its input where the type is not immediately available at node
- * intrinsification time. It is replaced by a {@link PiNode} once the type becomes constant.
- */
-@NodeInfo
-public class DeferredPiNode extends FloatingNode implements Canonicalizable {
-
-    @Input ValueNode object;
-    @Input ValueNode type;
-
-    public ValueNode object() {
-        return object;
-    }
-
-    public static DeferredPiNode create(ValueNode type, ValueNode object) {
-        return USE_GENERATED_NODES ? new DeferredPiNodeGen(type, object) : new DeferredPiNode(type, object);
-    }
-
-    protected DeferredPiNode(ValueNode type, ValueNode object) {
-        super(StampFactory.object());
-        this.type = type;
-        this.object = object;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (type.isConstant()) {
-            ResolvedJavaType javaType = tool.getConstantReflection().asJavaType(type.asConstant());
-            ObjectStamp objectStamp = (ObjectStamp) stamp();
-            return PiNode.create(object, javaType, objectStamp.isExactType(), objectStamp.nonNull());
-        }
-        return this;
-    }
-
-    @NodeIntrinsic
-    public static native <T> T piCast(Class<T> type, Object object);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Fri Sep 26 14:53:23 2014 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Edges.Type;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class EdgesTest extends GraalCompilerTest {
+
+    @NodeInfo
+    static class TestNode extends Node {
+        @Input NodeInputList<ValueNode> itail;
+        @Input ConstantNode i1;
+        @Input FloatingNode i2;
+
+        public static TestNode create() {
+            return USE_GENERATED_NODES ? new EdgesTest_TestNodeGen() : new TestNode();
+        }
+    }
+
+    StructuredGraph graph = new StructuredGraph();
+    TestNode node;
+    ConstantNode i1;
+    ConstantNode i2;
+    ConstantNode i3;
+    ConstantNode i4;
+    Edges inputs;
+
+    public EdgesTest() {
+        node = TestNode.create();
+        i1 = ConstantNode.forInt(1, graph);
+        i2 = ConstantNode.forDouble(1.0d, graph);
+        i3 = ConstantNode.forInt(4, graph);
+        i4 = ConstantNode.forInt(14, graph);
+        node.itail = new NodeInputList<>(node, new ValueNode[]{i3, i4});
+        node.i1 = i1;
+        node.i2 = i2;
+        graph.add(node);
+        inputs = node.getNodeClass().getEdges(Type.Inputs);
+    }
+
+    /**
+     * Checks that there are no checkcasts in {@link Edges#getNode(Node, int)}
+     */
+    @Test
+    public void test0() {
+        testMethod(getMethod("getNode", Node.class, int.class), inputs, node, 0);
+    }
+
+    /**
+     * Checks that there are no checkcasts in {@link Edges#getNodeList(Node, int)}
+     */
+    @Test
+    public void test1() {
+        testMethod(getMethod("getNodeList", Node.class, int.class), inputs, node, 2);
+    }
+
+    /**
+     * Checks that there are no checkcasts in {@link Edges#setNode(Node, int, Node)}
+     */
+    @Test
+    public void test2() {
+        testMethod(getMethod("setNode", Node.class, int.class, Node.class), inputs, node, 1, i2);
+    }
+
+    private void testMethod(Method method, Object receiver, Object... args) {
+        try {
+            // Invoke the method to ensure it has a type profile
+            for (int i = 0; i < 5000; i++) {
+                method.invoke(receiver, args);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        StructuredGraph g = parseProfiled(method);
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(g, context);
+        new CanonicalizerPhase(false).apply(g, context);
+        Assert.assertTrue(g.getNodes().filter(CheckCastNode.class).isEmpty());
+    }
+
+    private static Method getMethod(final String name, Class<?>... parameters) {
+        try {
+            return Edges.class.getDeclaredMethod(name, parameters);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FieldsSubstitutions.java	Fri Sep 26 14:45:10 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FieldsSubstitutions.java	Fri Sep 26 14:53:23 2014 +0200
@@ -25,8 +25,10 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.nodes.*;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Substitutions for improving the performance of some critical methods in {@link Fields}. These
@@ -38,6 +40,16 @@
 @ClassSubstitution(Fields.class)
 public class FieldsSubstitutions {
 
+    /**
+     * This substitution exists to force inline {@link Fields#getObject(Object, int, Class)}.
+     */
+    @SuppressWarnings("javadoc")
+    @SuppressFBWarnings
+    @MethodSubstitution(isStatic = false)
+    private static <T> T getObject(Fields thisObj, Object object, int index, Class<T> asType) {
+        return getObject(thisObj, object, index, asType);
+    }
+
     @MethodSubstitution
     private static <T> T getObject(Object object, long offset, Class<T> c) {
         return DeferredPiNode.piCast(c, UnsafeLoadNode.load(object, offset, Kind.Object, LocationIdentity.ANY_LOCATION));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Fri Sep 26 14:53:23 2014 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+//JaCoCo Exclude
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * A node for use in method substitutions or snippets that changes the type of its input where the
+ * type is not immediately available at {@link NodeIntrinsificationPhase intrinsification} time. It
+ * is replaced by a {@link PiNode} once the type becomes constant (which <b>must</b> happen).
+ */
+@NodeInfo
+public class DeferredPiNode extends FloatingNode implements Canonicalizable {
+
+    @Input ValueNode object;
+    @Input ValueNode type;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public static DeferredPiNode create(ValueNode type, ValueNode object) {
+        return USE_GENERATED_NODES ? new DeferredPiNodeGen(type, object) : new DeferredPiNode(type, object);
+    }
+
+    protected DeferredPiNode(ValueNode type, ValueNode object) {
+        super(StampFactory.object());
+        this.type = type;
+        this.object = object;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (type.isConstant()) {
+            ResolvedJavaType javaType = tool.getConstantReflection().asJavaType(type.asConstant());
+            ObjectStamp objectStamp = (ObjectStamp) stamp();
+            return PiNode.create(object, javaType, objectStamp.isExactType(), objectStamp.nonNull());
+        }
+        return this;
+    }
+
+    @NodeIntrinsic
+    public static native <T> T piCast(Class<T> type, Object object);
+}