# HG changeset patch # User Doug Simon # Date 1333020214 -7200 # Node ID a8c5283a835cca3e1a5436c367bda9dea8fe574d # Parent 9afe7747f9885288a40aeef34788c9c201b57741 added @Fold to folding methods during snippet intrinsification; replaced CardTableStartNode and CardTableShiftNode with @Fold methods diff -r 9afe7747f988 -r a8c5283a835c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java --- 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 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(); diff -r 9afe7747f988 -r a8c5283a835c graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- 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 { diff -r 9afe7747f988 -r a8c5283a835c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- 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; } }