# HG changeset patch # User Doug Simon # Date 1424118480 -3600 # Node ID e2fd58839d38fd4cda911ad962bd1407d2eca796 # Parent 7d3140f2de2e30f458deee658e1867ce16c780d1 exposed API for creating node intrinsic without first having an InvokeNode; added mechanism for NodeIntrinsics to be folded diff -r 7d3140f2de2e -r e2fd58839d38 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 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; } /** diff -r 7d3140f2de2e -r e2fd58839d38 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- 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 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 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 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 arguments = methodCallTargetNode.arguments(); + private Object[] prepareArguments(List 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;