# HG changeset patch # User Doug Simon # Date 1423145980 -3600 # Node ID ac9ad302e12f6d5f109f8a7fb717e7a920f5a6dc # Parent 2d67f05405437f98212bfeeccd5fda4abe01b9d9 added utility to GraphBuilderContext for generating a receiver null check from within an InvocationPlugin for a non-static method diff -r 2d67f0540543 -r ac9ad302e12f graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java --- 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); diff -r 2d67f0540543 -r ac9ad302e12f graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java --- 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 append(T fixed); - T append(T v); + 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; + } } diff -r 2d67f0540543 -r ac9ad302e12f graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- 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 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]; diff -r 2d67f0540543 -r ac9ad302e12f graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java --- 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); } } diff -r 2d67f0540543 -r ac9ad302e12f graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java --- 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; } diff -r 2d67f0540543 -r ac9ad302e12f graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- 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())); }