changeset 5175:a8c5283a835c

added @Fold to folding methods during snippet intrinsification; replaced CardTableStartNode and CardTableShiftNode with @Fold methods
author Doug Simon <doug.simon@oracle.com>
date Thu, 29 Mar 2012 13:23:34 +0200
parents 9afe7747f988
children af59b4dfc9e4
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java
diffstat 3 files changed, 94 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Thu Mar 29 13:22:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Thu Mar 29 13:23:34 2012 +0200
@@ -23,16 +23,18 @@
 package com.oracle.graal.compiler.phases;
 
 import java.lang.reflect.*;
+import java.util.*;
 
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.Fold;
 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.util.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
 
 public class SnippetIntrinsificationPhase extends Phase {
 
@@ -55,10 +57,12 @@
         RiResolvedMethod target = invoke.callTarget().targetMethod();
         NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
         if (intrinsic != null) {
+            assert target.getAnnotation(Node.Fold.class) == null;
+
             Class< ? >[] parameterTypes = CiUtil.signatureToTypes(target.signature(), target.holder());
 
             // Prepare the arguments for the reflective constructor call on the node class.
-            Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target);
+            Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false);
 
             // Create the new node instance.
             Class< ? > c = getNodeClass(target, intrinsic);
@@ -70,35 +74,65 @@
 
             // Clean up checkcast instructions inserted by javac if the return type is generic.
             cleanUpReturnCheckCast(newInstance);
+        } else if (target.getAnnotation(Node.Fold.class) != null) {
+            Class< ? >[] parameterTypes = CiUtil.signatureToTypes(target.signature(), target.holder());
+
+            // Prepare the arguments for the reflective method call
+            Object[] arguments = prepareArguments(invoke, parameterTypes, target, true);
+            Object receiver = null;
+            if (!invoke.callTarget().isStatic()) {
+                receiver = arguments[0];
+                arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray();
+            }
+
+            // Call the method
+            CiConstant constant = callMethod(target.signature().returnKind(false), target.holder().toJava(), target.name(), parameterTypes, receiver, arguments);
+
+            if (constant != null) {
+                // Replace the invoke with the result of the call
+                ConstantNode node = ConstantNode.forCiConstant(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);
+            }
         }
     }
 
-    private Object[] prepareArguments(Invoke invoke, Class< ? >[] parameterTypes, RiResolvedMethod target) {
+    /**
+     * 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
+     */
+    private Object[] prepareArguments(Invoke invoke, Class< ? >[] parameterTypes, RiResolvedMethod target, boolean folding) {
         NodeInputList<ValueNode> arguments = invoke.callTarget().arguments();
-        Object[] nodeConstructorArguments = new Object[arguments.size()];
-        for (int i = 0; i < nodeConstructorArguments.length; ++i) {
+        Object[] reflectionCallArguments = new Object[arguments.size()];
+        for (int i = 0; i < reflectionCallArguments.length; ++i) {
             int parameterIndex = i;
             if (!invoke.callTarget().isStatic()) {
                 parameterIndex--;
             }
             ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i));
-            ConstantNodeParameter param = CiUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target);
-            if (param != null) {
-                assert argument instanceof ConstantNode : "parameter " + parameterIndex + " must be compile time constant for " + invoke.callTarget().targetMethod();
+            if (folding || CiUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) {
+                assert argument instanceof ConstantNode : "parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.callTarget().targetMethod() + ": " + argument;
                 ConstantNode constantNode = (ConstantNode) argument;
                 Object o = constantNode.asConstant().boxedValue();
                 if (o instanceof Class< ? >) {
-                    nodeConstructorArguments[i] = runtime.getType((Class< ? >) o);
+                    reflectionCallArguments[i] = runtime.getType((Class< ? >) o);
                     parameterTypes[i] = RiResolvedType.class;
                 } else {
-                    nodeConstructorArguments[i] = o;
+                    reflectionCallArguments[i] = o;
                 }
             } else {
-                nodeConstructorArguments[i] = argument;
+                reflectionCallArguments[i] = argument;
                 parameterTypes[i] = ValueNode.class;
             }
         }
-        return nodeConstructorArguments;
+        return reflectionCallArguments;
     }
 
     private static Class< ? > getNodeClass(RiResolvedMethod target, NodeIntrinsic intrinsic) {
@@ -167,6 +201,28 @@
         }
     }
 
+    /**
+     * Calls a Java method via reflection.
+     */
+    private static CiConstant callMethod(CiKind 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 CiConstant.forBoxed(returnKind, result);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     public void cleanUpReturnCheckCast(Node newInstance) {
         if (newInstance instanceof ValueNode && ((ValueNode) newInstance).kind() != CiKind.Object) {
             StructuredGraph graph = (StructuredGraph) newInstance.graph();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Mar 29 13:22:25 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Mar 29 13:23:34 2012 +0200
@@ -77,7 +77,7 @@
 
     /**
      * Annotates a method that can be replaced by a compiler intrinsic.
-     * That is, a (resolved) call to the annotated method can be replaced
+     * A (resolved) call to the annotated method can be replaced
      * with an instance of the node class denoted by {@link #value()}.
      * For this reason, the signature of the annotated method must match
      * the signature of a constructor in the node class.
@@ -93,6 +93,21 @@
         Class value() default NodeIntrinsic.class;
     }
 
+
+    /**
+     * 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 {
+    }
+
+
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.METHOD)
     public static @interface NodePhase {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Thu Mar 29 13:22:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Thu Mar 29 13:23:34 2012 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.snippets;
 import com.oracle.max.cri.ci.*;
 import com.oracle.graal.cri.*;
+import com.oracle.graal.graph.Node.Fold;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -43,7 +44,6 @@
             throw new IndexOutOfBoundsException();
         }
 
-        // TODO remainder
         if (src == dest && srcPos < destPos) { // bad aliased case
             if ((length & 0x01) == 0) {
                 if ((length & 0x02) == 0) {
@@ -229,8 +229,8 @@
         }
         if (length > 0) {
             long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object);
-            int cardShift = CardTableShiftNode.get();
-            long cardStart = CardTableStartNode.get();
+            int cardShift = cardTableShift();
+            long cardStart = cardTableStart();
             long dstAddr = GetObjectAddressNode.get(dest);
             long start = (dstAddr + header + destPos * 8L) >>> cardShift;
             long end = (dstAddr + header + (destPos + length - 1) * 8L) >>> cardShift;
@@ -436,25 +436,13 @@
         }
     }
 
-    private static class CardTableShiftNode extends ConstantNode {
-        public CardTableShiftNode() {
-            super(CiConstant.forInt(CompilerImpl.getInstance().getConfig().cardtableShift));
-        }
-
-        @NodeIntrinsic
-        public static int get() {
-            throw new UnsupportedOperationException();
-        }
+    @Fold
+    private static int cardTableShift() {
+        return CompilerImpl.getInstance().getConfig().cardtableShift;
     }
 
-    private static class CardTableStartNode extends ConstantNode {
-        public CardTableStartNode() {
-            super(CiConstant.forLong(CompilerImpl.getInstance().getConfig().cardtableStartAddress));
-        }
-
-        @NodeIntrinsic
-        public static long get() {
-            throw new UnsupportedOperationException();
-        }
+    @Fold
+    private static long cardTableStart() {
+        return CompilerImpl.getInstance().getConfig().cardtableStartAddress;
     }
 }