changeset 19155:ac9ad302e12f

added utility to GraphBuilderContext for generating a receiver null check from within an InvocationPlugin for a non-static method
author Doug Simon <doug.simon@oracle.com>
date Thu, 05 Feb 2015 15:19:40 +0100
parents 2d67f0540543
children 247419385312
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java
diffstat 6 files changed, 92 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Thu Feb 05 14:34:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Thu Feb 05 15:19:40 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.java.GraphBuilderContext.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -47,9 +49,8 @@
                 if (objectStamp.isExactType() && objectStamp.nonNull()) {
                     mirror = builder.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), metaAccess));
                 } else {
-                    GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr));
                     StampProvider stampProvider = builder.getStampProvider();
-                    LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi));
+                    LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, makeNonNull(builder, rcvr)));
                     mirror = builder.append(new HubGetClassNode(builder.getMetaAccess(), hub));
                 }
                 builder.push(Kind.Object, mirror);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Feb 05 14:34:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Feb 05 15:19:40 2015 +0100
@@ -39,7 +39,7 @@
 
     <T extends FixedWithNextNode> T append(T fixed);
 
-    <T extends FloatingNode> T append(T v);
+    <T extends FloatingNode> T append(T value);
 
     StampProvider getStampProvider();
 
@@ -48,4 +48,15 @@
     Assumptions getAssumptions();
 
     void push(Kind kind, ValueNode value);
+
+    /**
+     * @see GuardingPiNode#makeNonNull(ValueNode)
+     */
+    static ValueNode makeNonNull(GraphBuilderContext builder, ValueNode value) {
+        ValueNode nonNullValue = GuardingPiNode.makeNonNull(value);
+        if (nonNullValue != value) {
+            builder.append((FixedWithNextNode) nonNullValue);
+        }
+        return nonNullValue;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 05 14:34:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 05 15:19:40 2015 +0100
@@ -38,11 +38,15 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.Node.ValueNumberable;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
-import com.oracle.graal.java.GraphBuilderPlugins.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InlineInvokePlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.LoopExplosionPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
@@ -800,14 +804,8 @@
                 }
 
                 if (graphBuilderPlugins != null) {
-                    InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod);
-                    if (plugin != null) {
-                        int beforeStackSize = frameState.stackSize;
-                        if (plugin.apply(this, args)) {
-                            assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize;
-                            return;
-                        }
-                        assert beforeStackSize == frameState.stackSize;
+                    if (tryUsingInvocationPlugin(args, targetMethod, resultType)) {
+                        return;
                     }
                 }
 
@@ -832,6 +830,36 @@
                 }
             }
 
+            private boolean tryUsingInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
+                InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod);
+                if (plugin != null) {
+                    int beforeStackSize = frameState.stackSize;
+                    boolean needsNullCheck = !targetMethod.isStatic() && !StampTool.isPointerNonNull(args[0].stamp());
+                    int nodeCount = currentGraph.getNodeCount();
+                    Mark mark = needsNullCheck ? currentGraph.getMark() : null;
+                    if (InvocationPlugin.execute(this, plugin, args)) {
+                        assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly";
+                        assert !needsNullCheck || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : "plugin needs to null check the receiver of " + targetMethod + ": " + args[0];
+                        return true;
+                    }
+                    assert nodeCount == currentGraph.getNodeCount() : "plugin that returns false must not create new nodes";
+                    assert beforeStackSize == frameState.stackSize : "plugin that returns false must modify the stack";
+                }
+                return false;
+            }
+
+            private boolean containsNullCheckOf(NodeIterable<Node> nodes, Node value) {
+                for (Node n : nodes) {
+                    if (n instanceof GuardingPiNode) {
+                        GuardingPiNode pi = (GuardingPiNode) n;
+                        if (pi.condition() instanceof IsNullNode) {
+                            return ((IsNullNode) pi.condition()).getValue() == value;
+                        }
+                    }
+                }
+                return false;
+            }
+
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args) {
                 BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, StructuredGraph.INVOCATION_ENTRY_BCI);
                 final FrameState[] lazyFrameState = new FrameState[1];
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Thu Feb 05 14:34:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Thu Feb 05 15:19:40 2015 +0100
@@ -66,52 +66,53 @@
      */
     public interface InvocationPlugin extends GraphBuilderPlugin {
         /**
-         * Tries to handle an invocation to a method with no arguments.
-         *
-         * @return {@code true} this plugin handled the invocation
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
          */
         default boolean apply(GraphBuilderContext builder) {
             throw invalidHandler(builder);
         }
 
         /**
-         * Tries to handle an invocation to a method with one argument.
-         *
-         * @return {@code true} this plugin handled the invocation
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
          */
         default boolean apply(GraphBuilderContext builder, ValueNode arg) {
             throw invalidHandler(builder, arg);
         }
 
         /**
-         * Tries to handle an invocation to a method with two arguments.
-         *
-         * @return {@code true} this plugin handled the invocation
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
          */
         default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
             throw invalidHandler(builder, arg1, arg2);
         }
 
         /**
-         * Tries to handle an invocation to a method with three arguments.
-         *
-         * @return {@code true} this plugin handled the invocation
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
          */
         default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
             throw invalidHandler(builder, arg1, arg2, arg3);
         }
 
-        default boolean apply(GraphBuilderContext builder, ValueNode[] args) {
+        /**
+         * Executes a given plugin against a set of invocation arguments by dispatching to the
+         * plugin's {@code apply(...)} method that matches the number of arguments.
+         *
+         * @return {@code true} if the plugin handled the invocation, {@code false} if the graph
+         *         builder should process the invoke further (e.g., by inlining it or creating an
+         *         {@link Invoke} node). A plugin that does not handle an invocation must not modify
+         *         the graph being constructed.
+         */
+        static boolean execute(GraphBuilderContext builder, InvocationPlugin plugin, ValueNode[] args) {
             if (args.length == 0) {
-                return apply(builder);
+                return plugin.apply(builder);
             } else if (args.length == 1) {
-                return apply(builder, args[0]);
+                return plugin.apply(builder, args[0]);
             } else if (args.length == 2) {
-                return apply(builder, args[0], args[1]);
+                return plugin.apply(builder, args[0], args[1]);
             } else if (args.length == 3) {
-                return apply(builder, args[0], args[1], args[2]);
+                return plugin.apply(builder, args[0], args[1], args[2]);
             } else {
-                throw invalidHandler(builder, args);
+                throw plugin.invalidHandler(builder, args);
             }
         }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Thu Feb 05 14:34:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Thu Feb 05 15:19:40 2015 +0100
@@ -22,21 +22,16 @@
  */
 package com.oracle.graal.java;
 
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.compiler.common.type.StampFactory.*;
+import static com.oracle.graal.java.GraphBuilderContext.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
 import com.oracle.graal.java.GraphBuilderPlugins.Registration;
 import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
@@ -93,14 +88,7 @@
         }
 
         public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ValueNode nonNullValue = value;
-            ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
-            if (!StampTool.isPointerNonNull(receiverStamp)) {
-                IsNullNode condition = builder.append(new IsNullNode(value));
-                Stamp stamp = receiverStamp.join(objectNonNull());
-                nonNullValue = builder.append(new GuardingPiNode(value, condition, true, NullCheckException, InvalidateReprofile, stamp));
-            }
-            builder.push(kind.getStackKind(), builder.append(new UnboxNode(nonNullValue, kind)));
+            builder.push(kind.getStackKind(), builder.append(new UnboxNode(makeNonNull(builder, value), kind)));
             return true;
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Thu Feb 05 14:34:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Thu Feb 05 15:19:40 2015 +0100
@@ -22,6 +22,10 @@
  */
 package com.oracle.graal.nodes;
 
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.compiler.common.type.StampFactory.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -65,6 +69,21 @@
         return action;
     }
 
+    /**
+     * Returns a node whose stamp is guaranteed to be {@linkplain StampTool#isPointerNonNull(Stamp)
+     * non-null}. If {@code value} already has such a stamp, then it is returned. Otherwise a fixed
+     * node guarding {@code value} is returned where the guard performs a null check.
+     */
+    public static ValueNode makeNonNull(ValueNode value) {
+        ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
+        if (!StampTool.isPointerNonNull(receiverStamp)) {
+            IsNullNode condition = value.graph().unique(new IsNullNode(value));
+            Stamp stamp = receiverStamp.join(objectNonNull());
+            return new GuardingPiNode(value, condition, true, NullCheckException, InvalidateReprofile, stamp);
+        }
+        return value;
+    }
+
     public GuardingPiNode(ValueNode object) {
         this(object, object.graph().unique(new IsNullNode(object)), true, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, object.stamp().join(StampFactory.objectNonNull()));
     }