changeset 20162:ba0f264a71cf

added support for inlining graphs derived from InvocationPlugins
author Doug Simon <doug.simon@oracle.com>
date Sat, 04 Apr 2015 19:47:04 +0200
parents 6adad2a0a24d
children c77b80772500
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java
diffstat 6 files changed, 260 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Fri Apr 03 17:49:43 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Sat Apr 04 19:47:04 2015 +0200
@@ -58,7 +58,9 @@
         /**
          * Determines if the receiver is constant.
          */
-        boolean isConstant();
+        default boolean isConstant() {
+            return false;
+        }
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Fri Apr 03 17:49:43 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Sat Apr 04 19:47:04 2015 +0200
@@ -68,11 +68,29 @@
     void notifyAfterConstantsBound(StructuredGraph specializedSnippet);
 
     /**
-     * Gets the graph that is a substitution for a given method.
+     * Gets a graph that is a substitution for a given method.
      *
      * @return the graph, if any, that is a substitution for {@code method}
      */
-    StructuredGraph getMethodSubstitution(ResolvedJavaMethod method);
+    default StructuredGraph getMethodSubstitution(ResolvedJavaMethod method) {
+        return getMethodSubstitution(method, false);
+    }
+
+    /**
+     * Gets a graph that is a substitution for a given method.
+     *
+     * @param fromBytecodeOnly only return a graph created by parsing the bytecode of another method
+     * @return the graph, if any, that is a substitution for {@code method}
+     */
+    StructuredGraph getMethodSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly);
+
+    /**
+     * Determines if there is a {@linkplain #getMethodSubstitution(ResolvedJavaMethod) substitution
+     * graph} for a given method.
+     *
+     * @return true iff there is a substitution graph available for {@code method}
+     */
+    boolean hasMethodSubstitution(ResolvedJavaMethod method);
 
     /**
      * Gets the method that is a substitution for a given method.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri Apr 03 17:49:43 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Sat Apr 04 19:47:04 2015 +0200
@@ -574,7 +574,7 @@
     }
 
     public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.getMethodSubstitutionMethod(target) != null;
+        return replacements.hasMethodSubstitution(target);
     }
 
     public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Sat Apr 04 19:47:04 2015 +0200
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2011, 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;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.util.*;
+
+/**
+ * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an
+ * {@link InvocationPlugin} for the method.
+ */
+public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
+
+    private final Providers providers;
+    private final SnippetReflectionProvider snippetReflection;
+    private final StructuredGraph graph;
+    private final ResolvedJavaMethod method;
+    private FixedWithNextNode lastInstr;
+    private ValueNode[] arguments;
+    private ValueNode returnValue;
+
+    public IntrinsicGraphBuilder(Providers providers, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod method) {
+        this.providers = providers;
+        this.snippetReflection = snippetReflection;
+        this.graph = new StructuredGraph(method, AllowAssumptions.YES);
+        this.method = method;
+        this.lastInstr = graph.start();
+
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)];
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!method.isStatic()) {
+            // add the receiver
+            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
+            FloatingNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, receiverStamp));
+            arguments[index] = receiver;
+            javaIndex = 1;
+            index = 1;
+        }
+        ResolvedJavaType accessingClass = method.getDeclaringClass();
+        for (int i = 0; i < max; i++) {
+            JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass);
+            Kind kind = type.getKind();
+            Stamp stamp;
+            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
+                stamp = StampFactory.declared((ResolvedJavaType) type);
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            FloatingNode param = graph.addWithoutUnique(new ParameterNode(index, stamp));
+            arguments[index] = param;
+            javaIndex += kind.getSlotCount();
+            index++;
+        }
+    }
+
+    private <T extends ValueNode> void updateLastInstruction(T v) {
+        if (v instanceof FixedNode) {
+            FixedNode fixedNode = (FixedNode) v;
+            lastInstr.setNext(fixedNode);
+            if (fixedNode instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                lastInstr = fixedWithNextNode;
+            } else {
+                lastInstr = null;
+            }
+        }
+    }
+
+    public <T extends ValueNode> T append(T v) {
+        if (v.graph() != null) {
+            return v;
+        }
+        T added = graph.addOrUnique(v);
+        if (added == v) {
+            updateLastInstruction(v);
+        }
+        return added;
+    }
+
+    public <T extends ValueNode> T recursiveAppend(T v) {
+        if (v.graph() != null) {
+            return v;
+        }
+        T added = graph.addOrUniqueWithInputs(v);
+        if (added == v) {
+            updateLastInstruction(v);
+        }
+        return added;
+    }
+
+    public void push(Kind kind, ValueNode value) {
+        assert kind != Kind.Void;
+        assert returnValue == null;
+        returnValue = value;
+    }
+
+    public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    public StampProvider getStampProvider() {
+        return providers.getStampProvider();
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    public Assumptions getAssumptions() {
+        return graph.getAssumptions();
+    }
+
+    public ConstantReflectionProvider getConstantReflection() {
+        return providers.getConstantReflection();
+    }
+
+    public SnippetReflectionProvider getSnippetReflection() {
+        return snippetReflection;
+    }
+
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+
+    public FrameState createStateAfter() {
+        return getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
+    }
+
+    public GraphBuilderContext getParent() {
+        return null;
+    }
+
+    public ResolvedJavaMethod getRootMethod() {
+        return method;
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    public int bci() {
+        return -1;
+    }
+
+    public InvokeKind getInvokeKind() {
+        return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual;
+    }
+
+    public JavaType getInvokeReturnType() {
+        return method.getSignature().getReturnType(method.getDeclaringClass());
+    }
+
+    public int getDepth() {
+        return 0;
+    }
+
+    public boolean parsingReplacement() {
+        return true;
+    }
+
+    public Replacement getReplacement() {
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    public boolean eagerResolving() {
+        return true;
+    }
+
+    public BailoutException bailout(String string) {
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    public ValueNode get() {
+        return arguments[0];
+    }
+
+    public StructuredGraph buildGraph(InvocationPlugin plugin) {
+        Receiver receiver = method.isStatic() ? null : this;
+        InvocationPlugin.execute(this, method, plugin, receiver, arguments);
+        assert (returnValue != null) == (method.getSignature().getReturnKind() != Kind.Void);
+        append(new ReturnNode(returnValue));
+        return graph;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Apr 03 17:49:43 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sat Apr 04 19:47:04 2015 +0200
@@ -46,8 +46,7 @@
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
 import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.*;
@@ -90,8 +89,8 @@
      * Determines whether a given method should be inlined based on whether it has a substitution or
      * whether the inlining context is already within a substitution.
      *
-     * @return an {@link InlineInfo} object specifying how {@code method} is to be inlined or null
-     *         if it should not be inlined based on substitution related criteria
+     * @return an object specifying how {@code method} is to be inlined or null if it should not be
+     *         inlined based on substitution related criteria
      */
     public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
         ResolvedJavaMethod subst = getMethodSubstitutionMethod(method);
@@ -337,7 +336,13 @@
     }
 
     @Override
-    public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) {
+    public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original, boolean fromBytecodeOnly) {
+        if (!fromBytecodeOnly) {
+            InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(original);
+            if (plugin != null) {
+                return new IntrinsicGraphBuilder(providers, snippetReflection, original).buildGraph(plugin);
+            }
+        }
         ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName());
         ResolvedJavaMethod substitute = cr == null ? null : cr.methodSubstitutions.get(original);
         if (substitute == null) {
@@ -623,7 +628,7 @@
             // to be valid for the entire run of the VM.
             final StructuredGraph graph = new StructuredGraph(methodToParse, AllowAssumptions.NO);
 
-            // They will also never be never be evolved or have breakpoints set in them
+            // They will also never evolve or have breakpoints set in them
             graph.disableInlinedMethodRecording();
 
             try (Scope s = Debug.scope("buildInitialGraph", graph)) {
@@ -795,6 +800,10 @@
         return cr != null && cr.forcedSubstitutions.contains(method);
     }
 
+    public boolean hasMethodSubstitution(ResolvedJavaMethod method) {
+        return graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method) != null || getMethodSubstitutionMethod(method) != null;
+    }
+
     @Override
     public ResolvedJavaMethod getMethodSubstitutionMethod(ResolvedJavaMethod original) {
         ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName());
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Apr 03 17:49:43 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Sat Apr 04 19:47:04 2015 +0200
@@ -108,7 +108,7 @@
      * lowered}.
      */
     protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) {
-        StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod());
+        StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod(), true);
         if (methodSubstitution != null) {
             methodSubstitution = methodSubstitution.copy();
             if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) {