changeset 19419:e2fd58839d38

exposed API for creating node intrinsic without first having an InvokeNode; added mechanism for NodeIntrinsics to be folded
author Doug Simon <doug.simon@oracle.com>
date Mon, 16 Feb 2015 21:28:00 +0100
parents 7d3140f2de2e
children 87a2901b1f42
files graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java
diffstat 2 files changed, 79 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Feb 16 21:12:51 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Feb 16 21:28:00 2015 +0100
@@ -160,6 +160,14 @@
          * ignored and can therefore safely be {@code null}.
          */
         boolean setStampFromReturnType() default false;
+
+        /**
+         * Determines if this intrinsic can be compile-time executed. An attempt to execute a call
+         * (via reflection) to this intrinsic at compile-time will be made if all of its arguments
+         * are compile-time constant. If the execution succeeds without an exception, the result is
+         * inserted as a constant node in the graph.
+         */
+        boolean foldable() default false;
     }
 
     /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Feb 16 21:12:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Feb 16 21:28:00 2015 +0100
@@ -80,21 +80,12 @@
 
         NodeIntrinsic intrinsic = getIntrinsic(target);
         if (intrinsic != null) {
-            assert target.getAnnotation(Fold.class) == null;
-            assert target.isStatic() : "node intrinsic must be static: " + target;
-
-            ResolvedJavaType[] parameterTypes = resolveJavaTypes(target.toParameterTypes(), declaringClass);
-
-            // Prepare the arguments for the reflective constructor call on the node class.
-            Object[] nodeConstructorArguments = prepareArguments(methodCallTargetNode, parameterTypes, target, false);
-            if (nodeConstructorArguments == null) {
+            Stamp stamp = methodCallTargetNode.invoke().asNode().stamp();
+            Node newInstance = createIntrinsicNode(methodCallTargetNode.arguments(), stamp, target, graph, intrinsic);
+            if (newInstance == null) {
                 return false;
             }
 
-            // Create the new node instance.
-            ResolvedJavaType c = getNodeClass(target, intrinsic);
-            Node newInstance = createNodeInstance(graph, c, parameterTypes, methodCallTargetNode.invoke().asNode().stamp(), intrinsic.setStampFromReturnType(), nodeConstructorArguments);
-
             // Replace the invoke with the new node.
             newInstance = graph.addOrUnique(newInstance);
             methodCallTargetNode.invoke().intrinsify(newInstance);
@@ -103,21 +94,10 @@
             cleanUpReturnList.add(newInstance);
         } else if (isFoldable(target)) {
             ResolvedJavaType[] parameterTypes = resolveJavaTypes(target.toParameterTypes(), declaringClass);
-
-            // Prepare the arguments for the reflective method call
-            JavaConstant[] arguments = (JavaConstant[]) prepareArguments(methodCallTargetNode, parameterTypes, target, true);
-            if (arguments == null) {
+            JavaConstant constant = tryFold(methodCallTargetNode.arguments(), parameterTypes, target);
+            if (constant == COULD_NOT_FOLD) {
                 return false;
             }
-            JavaConstant receiver = null;
-            if (!methodCallTargetNode.isStatic()) {
-                receiver = arguments[0];
-                arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
-                parameterTypes = Arrays.copyOfRange(parameterTypes, 1, parameterTypes.length);
-            }
-
-            // Call the method
-            JavaConstant constant = target.invoke(receiver, arguments);
 
             if (constant != null) {
                 // Replace the invoke with the result of the call
@@ -134,6 +114,69 @@
         return true;
     }
 
+    @SuppressWarnings("serial") private static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) {
+    };
+
+    public JavaConstant tryFold(List<ValueNode> args, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target) {
+        JavaConstant[] reflectArgs = (JavaConstant[]) prepareArguments(args, parameterTypes, target, true);
+        if (reflectArgs == null) {
+            return COULD_NOT_FOLD;
+        }
+        JavaConstant receiver = null;
+        if (!target.isStatic()) {
+            receiver = reflectArgs[0];
+            reflectArgs = Arrays.copyOfRange(reflectArgs, 1, reflectArgs.length);
+        }
+
+        // Call the method
+        return target.invoke(receiver, reflectArgs);
+    }
+
+    private static boolean areAllConstant(List<ValueNode> arguments) {
+        for (ValueNode arg : arguments) {
+            if (!arg.isConstant()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Attempts to create a node to replace a call to a {@link NodeIntrinsic} annotated method.
+     *
+     * @param arguments the arguments of the call
+     * @param stamp the stamp to use for the returned node
+     * @param method the method annotated with {@link NodeIntrinsic}
+     * @param graph the graph into which the created node will be added
+     * @return a {@link ConstantNode} if the intrinsic could be
+     *         {@linkplain NodeIntrinsic#foldable() folded}, {@code null} if intrinsification could
+     *         not (yet) be performed, otherwise the node representing the intrinsic
+     */
+    public ValueNode createIntrinsicNode(List<ValueNode> arguments, Stamp stamp, ResolvedJavaMethod method, StructuredGraph graph, NodeIntrinsic intrinsic) {
+        assert method.getAnnotation(Fold.class) == null;
+        assert method.isStatic() : "node intrinsic must be static: " + method;
+
+        ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
+
+        if (intrinsic.foldable() && areAllConstant(arguments)) {
+            JavaConstant res = tryFold(arguments, parameterTypes, method);
+            if (res != COULD_NOT_FOLD) {
+                assert res != null;
+                return ConstantNode.forConstant(res, providers.getMetaAccess());
+            }
+        }
+
+        // Prepare the arguments for the reflective constructor call on the node class.
+        Object[] nodeConstructorArguments = prepareArguments(arguments, parameterTypes, method, false);
+        if (nodeConstructorArguments == null) {
+            return null;
+        }
+
+        // Create the new node instance.
+        ResolvedJavaType c = getNodeClass(method, intrinsic);
+        return createNodeInstance(graph, c, parameterTypes, stamp, intrinsic.setStampFromReturnType(), nodeConstructorArguments);
+    }
+
     /**
      * Permits a subclass to override the default definition of "intrinsic".
      */
@@ -156,12 +199,11 @@
      * @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(MethodCallTargetNode methodCallTargetNode, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
-        NodeInputList<ValueNode> arguments = methodCallTargetNode.arguments();
+    private Object[] prepareArguments(List<ValueNode> arguments, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
         Object[] reflectionCallArguments = folding ? new JavaConstant[arguments.size()] : new Object[arguments.size()];
         for (int i = 0; i < reflectionCallArguments.length; ++i) {
             int parameterIndex = i;
-            if (!methodCallTargetNode.isStatic()) {
+            if (!target.isStatic()) {
                 parameterIndex--;
             }
             ValueNode argument = arguments.get(i);
@@ -226,7 +268,7 @@
         return result;
     }
 
-    protected Node createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
+    protected ValueNode createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
                     Object[] nodeConstructorArguments) {
         ResolvedJavaMethod constructor = null;
         Object[] arguments = null;