# HG changeset patch # User Doug Simon # Date 1426800702 -3600 # Node ID 9b669776bf8a3b36a2665d2f868291798406d42a # Parent 71040f48cc34087ac35e4f269b92de9b2ea7e169 added null checking for the receiver when inlining or applying an InvocationPlugin during graph parsing diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Thu Mar 19 22:31:42 2015 +0100 @@ -124,17 +124,6 @@ */ Replacement getReplacement(); - /** - * @see GuardingPiNode#nullCheckedValue(ValueNode) - */ - static ValueNode nullCheckedValue(GraphBuilderContext builder, ValueNode value) { - ValueNode nonNullValue = GuardingPiNode.nullCheckedValue(value); - if (nonNullValue != value) { - builder.append((FixedWithNextNode) nonNullValue); - } - return nonNullValue; - } - boolean eagerResolving(); BailoutException bailout(String string); diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java Thu Mar 19 22:31:42 2015 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; import com.oracle.graal.nodes.*; /** @@ -36,43 +37,43 @@ /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { - throw invalidHandler(b, targetMethod); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + throw invalidHandler(b, targetMethod, receiver); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { - throw invalidHandler(b, targetMethod, arg); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + throw invalidHandler(b, targetMethod, receiver, arg); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) { - throw invalidHandler(b, targetMethod, arg1, arg2); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) { - throw invalidHandler(b, targetMethod, arg1, arg2, arg3); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { - throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { - throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5); } default ResolvedJavaMethod getSubstitute() { @@ -84,30 +85,52 @@ * {@code apply(...)} method that matches the number of arguments. * * @param targetMethod the method for which plugin is being applied + * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static + * @param args the remaining arguments * @return {@code true} if the plugin handled the invocation of {@code targetMethod} * {@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 b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) { - if (args.length == 0) { - return plugin.apply(b, targetMethod); - } else if (args.length == 1) { - return plugin.apply(b, targetMethod, args[0]); - } else if (args.length == 2) { - return plugin.apply(b, targetMethod, args[0], args[1]); - } else if (args.length == 3) { - return plugin.apply(b, targetMethod, args[0], args[1], args[2]); - } else if (args.length == 4) { - return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]); - } else if (args.length == 5) { - return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]); + static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, Receiver receiver, ValueNode[] args) { + if (receiver != null) { + assert !targetMethod.isStatic(); + assert args.length > 0; + if (args.length == 1) { + return plugin.apply(b, targetMethod, receiver); + } else if (args.length == 2) { + return plugin.apply(b, targetMethod, receiver, args[1]); + } else if (args.length == 3) { + return plugin.apply(b, targetMethod, receiver, args[1], args[2]); + } else if (args.length == 4) { + return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3]); + } else if (args.length == 5) { + return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3], args[4]); + } else { + throw plugin.invalidHandler(b, targetMethod, receiver, args); + } } else { - throw plugin.invalidHandler(b, targetMethod, args); + assert targetMethod.isStatic(); + if (args.length == 0) { + return plugin.apply(b, targetMethod, null); + } else if (args.length == 1) { + return plugin.apply(b, targetMethod, null, args[0]); + } else if (args.length == 2) { + return plugin.apply(b, targetMethod, null, args[0], args[1]); + } else if (args.length == 3) { + return plugin.apply(b, targetMethod, null, args[0], args[1], args[2]); + } else if (args.length == 4) { + return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3]); + } else if (args.length == 5) { + return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3], args[4]); + } else { + throw plugin.invalidHandler(b, targetMethod, receiver, args); + } + } } - default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) { + default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") Receiver receiver, ValueNode... args) { return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length); } diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Thu Mar 19 22:31:42 2015 +0100 @@ -33,6 +33,7 @@ import com.oracle.graal.graph.Node; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; /** * Manages a set of {@link InvocationPlugin}s. @@ -40,14 +41,29 @@ public class InvocationPlugins { /** - * Sentinel class for use with + * Access to the receiver in an {@link InvocationPlugin} for a non-static method. The class + * literal for this interface must be used with * {@link InvocationPlugins#register(InvocationPlugin, Class, String, Class...)} to denote the - * receiver argument for a non-static method. + * receiver argument for such a non-static method. */ - public static final class Receiver { - private Receiver() { - throw GraalInternalError.shouldNotReachHere(); - } + public interface Receiver { + /** + * Gets the receiver value, null checking it first if necessary. + * + * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode) + * non-null} stamp + */ + ValueNode get(); + + /** + * Determines if the receiver is constant. + */ + boolean isConstant(); + + /** + * Determines if the receiver is the null constant. + */ + boolean isNullConstant(); } /** @@ -344,11 +360,12 @@ Class[] sig = method.getParameterTypes(); assert sig[0] == GraphBuilderContext.class; assert sig[1] == ResolvedJavaMethod.class; - assert Arrays.asList(Arrays.copyOfRange(sig, 2, sig.length)).stream().allMatch(c -> c == ValueNode.class); - while (sigs.size() < sig.length - 1) { + assert sig[2] == Receiver.class; + assert Arrays.asList(Arrays.copyOfRange(sig, 3, sig.length)).stream().allMatch(c -> c == ValueNode.class); + while (sigs.size() < sig.length - 2) { sigs.add(null); } - sigs.set(sig.length - 2, sig); + sigs.set(sig.length - 3, sig); } } assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null), @@ -362,7 +379,7 @@ assert !p.registrations.contains(method) : "a plugin is already registered for " + method; p = p.parent; } - int arguments = method.argumentTypes.length; + int arguments = method.isStatic ? method.argumentTypes.length : method.argumentTypes.length - 1; assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method); for (Method m : plugin.getClass().getDeclaredMethods()) { if (m.getName().equals("apply")) { diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu Mar 19 22:31:42 2015 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.hotspot.meta; -import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import com.oracle.graal.api.code.*; @@ -30,9 +29,10 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; @@ -84,14 +84,15 @@ private static void registerObjectPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Object.class); r.register1("getClass", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode rcvr = receiver.get(); ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp(); ValueNode mirror; if (objectStamp.isExactType() && objectStamp.nonNull() && !GraalOptions.ImmutableCode.getValue()) { mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess())); } else { StampProvider stampProvider = b.getStampProvider(); - LoadHubNode hub = b.append(new LoadHubNode(stampProvider, nullCheckedValue(b, rcvr))); + LoadHubNode hub = b.append(new LoadHubNode(stampProvider, rcvr)); mirror = b.append(new HubGetClassNode(b.getMetaAccess(), hub)); } b.push(Kind.Object, mirror); @@ -103,7 +104,7 @@ private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) { Registration r = new Registration(plugins, System.class); r.register0("currentTimeMillis", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long)); b.push(Kind.Long, b.append(foreignCall)); foreignCall.setStateAfter(b.createStateAfter()); @@ -111,7 +112,7 @@ } }); r.register0("nanoTime", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long)); b.push(Kind.Long, b.append(foreignCall)); foreignCall.setStateAfter(b.createStateAfter()); @@ -123,7 +124,7 @@ private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, HotSpotVMConfig config) { Registration r = new Registration(plugins, Thread.class); r.register0("currentThread", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind())); ConstantLocationNode location = b.append(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset)); boolean compressible = false; @@ -139,9 +140,9 @@ private static void registerStableOptionPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, StableOptionValue.class); r.register1("getValue", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) { - if (rcvr.isConstant() && !rcvr.isNullConstant()) { - Object object = ((HotSpotObjectConstantImpl) rcvr.asConstant()).object(); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + if (receiver.isConstant() && !receiver.isNullConstant()) { + Object object = ((HotSpotObjectConstantImpl) receiver.get().asConstant()).object(); StableOptionValue option = (StableOptionValue) object; ConstantNode value = b.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess())); b.push(Kind.Object, value); diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu Mar 19 22:31:42 2015 +0100 @@ -38,10 +38,11 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.debug.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -333,11 +334,8 @@ protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind); private void genLoadIndexed(Kind kind) { - - emitExplicitExceptions(frameState.peek(1), frameState.peek(0)); - ValueNode index = frameState.ipop(); - ValueNode array = frameState.apop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); if (!tryLoadIndexedPlugin(kind, index, array)) { frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind))); } @@ -360,11 +358,9 @@ protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value); private void genStoreIndexed(Kind kind) { - emitExplicitExceptions(frameState.peek(2), frameState.peek(1)); - ValueNode value = frameState.pop(kind.getStackKind()); ValueNode index = frameState.ipop(); - ValueNode array = frameState.apop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); genStoreIndexed(array, index, kind, value); } @@ -832,10 +828,8 @@ protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field); private void genGetField(JavaField field) { - emitExplicitExceptions(frameState.peek(0), null); - Kind kind = field.getKind(); - ValueNode receiver = frameState.apop(); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) { @@ -846,36 +840,53 @@ } } - protected abstract void emitNullCheck(ValueNode receiver); + /** + * Emits control flow to null check a receiver if it's stamp does not indicate it is + * {@linkplain StampTool#isPointerNonNull always non-null}. + * + * @return the receiver with a stamp indicating non-nullness + */ + protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver); - protected abstract void emitBoundsCheck(ValueNode index, ValueNode length); + /** + * Emits control flow to check an array index is within bounds of an array's length. + * + * @param index the index to check + * @param length the length of the array being indexed + */ + protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length); private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); protected abstract ValueNode genArrayLength(ValueNode x); - protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) { + /** + * @param receiver the receiver of an object based operation + * @param index the index of an array based operation that is to be tested for out of bounds. + * This is null for a non-array operation. + * @return the receiver value possibly modified to have a tighter stamp + */ + protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { assert receiver != null; if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null || (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) { - return; + return receiver; } - emitNullCheck(receiver); - if (outOfBoundsIndex != null) { - ValueNode length = append(genArrayLength(receiver)); - emitBoundsCheck(outOfBoundsIndex, length); + ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); + if (index != null) { + ValueNode length = append(genArrayLength(nonNullReceiver)); + emitExplicitBoundsCheck(index, length); } EXPLICIT_EXCEPTIONS.increment(); + return nonNullReceiver; } protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value); private void genPutField(JavaField field) { - emitExplicitExceptions(frameState.peek(1), null); - ValueNode value = frameState.pop(field.getKind().getStackKind()); - ValueNode receiver = frameState.apop(); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { genStoreField(receiver, (ResolvedJavaField) field, value); } else { diff -r 71040f48cc34 -r 9b669776bf8a 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 Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Mar 19 22:31:42 2015 +0100 @@ -27,9 +27,10 @@ import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.compiler.common.GraalInternalError.*; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.graph.iterators.NodePredicates.*; +import static com.oracle.graal.compiler.common.type.StampFactory.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; import static com.oracle.graal.nodes.StructuredGraph.*; +import static com.oracle.graal.nodes.type.StampTool.*; import static java.lang.String.*; import java.util.*; @@ -49,6 +50,7 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; @@ -233,6 +235,47 @@ } } + static class InvocationPluginReceiver implements Receiver { + final BytecodeParser parser; + ValueNode[] args; + ValueNode value; + + public InvocationPluginReceiver(BytecodeParser parser) { + this.parser = parser; + } + + @Override + public ValueNode get() { + assert args != null : "Cannot get the receiver of a static method"; + if (value == null) { + value = parser.nullCheckedValue(args[0]); + if (value != args[0]) { + args[0] = value; + } + } + return value; + } + + @Override + public boolean isConstant() { + return args[0].isConstant(); + } + + @Override + public boolean isNullConstant() { + return args[0].isNullConstant(); + } + + InvocationPluginReceiver init(ResolvedJavaMethod targetMethod, ValueNode[] newArgs) { + if (!targetMethod.isStatic()) { + this.args = newArgs; + this.value = null; + return this; + } + return null; + } + } + public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext { private BciBlockMapping blockMap; @@ -258,6 +301,7 @@ private Stack explodeLoopsContext; private int nextPeelIteration = 1; private boolean controlFlowSplit; + private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this); private FixedWithNextNode[] firstInstructionArray; private HIRFrameStateBuilder[] entryStateArray; @@ -385,6 +429,28 @@ } } + /** + * Gets a version of a given value that has a + * {@linkplain StampTool#isPointerNonNull(ValueNode) non-null} stamp. + */ + ValueNode nullCheckedValue(ValueNode value) { + if (!StampTool.isPointerNonNull(value.stamp())) { + IsNullNode condition = currentGraph.unique(new IsNullNode(value)); + ObjectStamp receiverStamp = (ObjectStamp) value.stamp(); + Stamp stamp = receiverStamp.join(objectNonNull()); + FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); + PiNode nonNullReceiver = currentGraph.unique(new PiNode(value, stamp)); + nonNullReceiver.setGuard(fixedGuard); + // TODO: Propogating the non-null into the frame state would + // remove subsequent null-checks on the same value. However, + // it currently causes an assertion failure when merging states. + // + // frameState.replace(value, nonNullReceiver); + return nonNullReceiver; + } + return value; + } + private void detectLoops(FixedNode startInstruction) { NodeBitMap visited = currentGraph.createNodeBitMap(); NodeBitMap active = currentGraph.createNodeBitMap(); @@ -947,21 +1013,24 @@ } @Override - protected void emitNullCheck(ValueNode receiver) { + protected ValueNode emitExplicitNullCheck(ValueNode receiver) { if (StampTool.isPointerNonNull(receiver.stamp())) { - return; + return receiver; } BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class)); AbstractBeginNode falseSucc = currentGraph.add(new BeginNode()); + PiNode nonNullReceiver = currentGraph.unique(new PiNode(receiver, receiver.stamp().join(objectNonNull()))); + nonNullReceiver.setGuard(falseSucc); append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01)); lastInstr = falseSucc; exception.setStateAfter(createFrameState(bci())); exception.setNext(handleException(exception, bci())); + return nonNullReceiver; } @Override - protected void emitBoundsCheck(ValueNode index, ValueNode length) { + protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { AbstractBeginNode trueSucc = currentGraph.add(new BeginNode()); BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); append(new IfNode(currentGraph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); @@ -1102,11 +1171,16 @@ returnType = returnType.resolve(targetMethod.getDeclaringClass()); } if (invokeKind.hasReceiver()) { - emitExplicitExceptions(args[0], null); + args[0] = emitExplicitExceptions(args[0], null); if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) { JavaTypeProfile profile = profilingInfo.getTypeProfile(bci()); args[0] = TypeProfileProxyNode.proxify(args[0], profile); } + + if (args[0].isNullConstant()) { + append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); + return; + } } if (tryGenericInvocationPlugin(args, targetMethod)) { @@ -1176,24 +1250,30 @@ this.mark = currentGraph.getMark(); } + String error(String format, Object... a) { + return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess)); + } + boolean check(boolean pluginResult) { if (pluginResult == true) { - assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly " + targetMethod; + assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : error("plugin manipulated the stack incorrectly"); NodeIterable newNodes = currentGraph.getNewNodes(mark); - assert !needsNullCheck || args[0].usages().filter(isNotA(FrameState.class)).isEmpty() || containsNullCheckOf(newNodes, args[0]) : format( - "plugin needs to null check the receiver of %s: receiver=%s%n\tplugin at %s", targetMethod.format("%H.%n(%p)"), args[0], - plugin.getApplySourceLocation(metaAccess)); + assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]); for (Node n : newNodes) { if (n instanceof StateSplit) { StateSplit stateSplit = (StateSplit) n; - assert stateSplit.stateAfter() != null : format("%s node added by plugin for %s need to have a non-null frame state: %s%n\tplugin at %s", - StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit, plugin.getApplySourceLocation(metaAccess)); + assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(), + targetMethod.format("%H.%n(%p)"), stateSplit); } } - graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes); + try { + graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes); + } catch (Throwable t) { + throw new AssertionError(error("Error in plugin"), t); + } } else { - 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"; + assert nodeCount == currentGraph.getNodeCount() : error("plugin that returns false must not create new nodes"); + assert beforeStackSize == frameState.stackSize : error("plugin that returns false must modify the stack"); } return true; } @@ -1203,7 +1283,7 @@ InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); if (plugin != null) { InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; - if (InvocationPlugin.execute(this, targetMethod, plugin, args)) { + if (InvocationPlugin.execute(this, targetMethod, plugin, invocationPluginReceiver.init(targetMethod, args), args)) { assert assertions.check(true); return true; } @@ -1217,18 +1297,6 @@ return plugin != null && plugin.apply(this, targetMethod, args); } - 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 boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, JavaType returnType) { InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin(); if (plugin == null || !invokeKind.isDirect() || !targetMethod.canBeInlined()) { @@ -1318,6 +1386,9 @@ private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) { BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext); HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, currentGraph); + if (!targetMethod.isStatic()) { + args[0] = nullCheckedValue(args[0]); + } startFrameState.initializeFromArgumentsArray(args); parser.build(this.lastInstr, startFrameState); diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Thu Mar 19 22:31:42 2015 +0100 @@ -297,7 +297,7 @@ ((PhiNode) currentValue).addInput(otherValue); return currentValue; } else if (currentValue != otherValue) { - assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for changed locals and all stack slots"; + assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { return null; } @@ -958,4 +958,17 @@ } return false; } + + public void replace(ValueNode oldValue, ValueNode newValue) { + for (int i = 0; i < locals.length; i++) { + if (locals[i] == oldValue) { + locals[i] = newValue; + } + } + for (int i = 0; i < stackSize; i++) { + if (stack[i] == oldValue) { + stack[i] = newValue; + } + } + } } diff -r 71040f48cc34 -r 9b669776bf8a 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 Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Thu Mar 19 22:31:42 2015 +0100 @@ -22,10 +22,6 @@ */ 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.*; @@ -70,21 +66,6 @@ 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 nullCheckedValue(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())); } diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java Thu Mar 19 22:31:42 2015 +0100 @@ -79,6 +79,11 @@ } @Test + public void testFoo() throws Exception { + testGraph("unsafeDirectMemoryRead"); + } + + @Test public void testUnsafeSubstitutions() throws Exception { test("unsafeCompareAndSwapInt", unsafe, supply(() -> new Foo()), fooOffset("i")); @@ -108,32 +113,34 @@ testGraph("unsafeDirectMemoryRead"); testGraph("unsafeDirectMemoryWrite"); - test("unsafeCompareAndSwapInt", unsafe, supply(() -> new Foo()), fooOffset("i")); - test("unsafeCompareAndSwapLong", unsafe, supply(() -> new Foo()), fooOffset("l")); - test("unsafeCompareAndSwapObject", unsafe, supply(() -> new Foo()), fooOffset("o")); + long address = unsafe.allocateMemory(8 * Kind.values().length); + for (Unsafe unsafeArg : new Unsafe[]{unsafe, null}) { + test("unsafeCompareAndSwapInt", unsafeArg, supply(() -> new Foo()), fooOffset("i")); + test("unsafeCompareAndSwapLong", unsafeArg, supply(() -> new Foo()), fooOffset("l")); + test("unsafeCompareAndSwapObject", unsafeArg, supply(() -> new Foo()), fooOffset("o")); - test("unsafeGetBoolean", unsafe, supply(() -> new Foo()), fooOffset("z")); - test("unsafeGetByte", unsafe, supply(() -> new Foo()), fooOffset("b")); - test("unsafeGetShort", unsafe, supply(() -> new Foo()), fooOffset("s")); - test("unsafeGetChar", unsafe, supply(() -> new Foo()), fooOffset("c")); - test("unsafeGetInt", unsafe, supply(() -> new Foo()), fooOffset("i")); - test("unsafeGetLong", unsafe, supply(() -> new Foo()), fooOffset("l")); - test("unsafeGetFloat", unsafe, supply(() -> new Foo()), fooOffset("f")); - test("unsafeGetDouble", unsafe, supply(() -> new Foo()), fooOffset("d")); - test("unsafeGetObject", unsafe, supply(() -> new Foo()), fooOffset("o")); + test("unsafeGetBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z")); + test("unsafeGetByte", unsafeArg, supply(() -> new Foo()), fooOffset("b")); + test("unsafeGetShort", unsafeArg, supply(() -> new Foo()), fooOffset("s")); + test("unsafeGetChar", unsafeArg, supply(() -> new Foo()), fooOffset("c")); + test("unsafeGetInt", unsafeArg, supply(() -> new Foo()), fooOffset("i")); + test("unsafeGetLong", unsafeArg, supply(() -> new Foo()), fooOffset("l")); + test("unsafeGetFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f")); + test("unsafeGetDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d")); + test("unsafeGetObject", unsafeArg, supply(() -> new Foo()), fooOffset("o")); - test("unsafePutBoolean", unsafe, supply(() -> new Foo()), fooOffset("z"), true); - test("unsafePutByte", unsafe, supply(() -> new Foo()), fooOffset("b"), (byte) 87); - test("unsafePutShort", unsafe, supply(() -> new Foo()), fooOffset("s"), (short) -93); - test("unsafePutChar", unsafe, supply(() -> new Foo()), fooOffset("c"), 'A'); - test("unsafePutInt", unsafe, supply(() -> new Foo()), fooOffset("i"), 42); - test("unsafePutFloat", unsafe, supply(() -> new Foo()), fooOffset("f"), 58.0F); - test("unsafePutDouble", unsafe, supply(() -> new Foo()), fooOffset("d"), -28736.243465D); - test("unsafePutObject", unsafe, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3"); + test("unsafePutBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z"), true); + test("unsafePutByte", unsafeArg, supply(() -> new Foo()), fooOffset("b"), (byte) 87); + test("unsafePutShort", unsafeArg, supply(() -> new Foo()), fooOffset("s"), (short) -93); + test("unsafePutChar", unsafeArg, supply(() -> new Foo()), fooOffset("c"), 'A'); + test("unsafePutInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"), 42); + test("unsafePutFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f"), 58.0F); + test("unsafePutDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d"), -28736.243465D); + test("unsafePutObject", unsafeArg, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3"); - long address = unsafe.allocateMemory(8 * Kind.values().length); - test("unsafeDirectMemoryRead", unsafe, address); - test("unsafeDirectMemoryWrite", unsafe, address, 0xCAFEBABEDEADBABEL); + test("unsafeDirectMemoryRead", unsafeArg, address); + test("unsafeDirectMemoryWrite", unsafeArg, address, 0xCAFEBABEDEADBABEL); + } unsafe.freeMemory(address); } diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Thu Mar 19 22:31:42 2015 +0100 @@ -23,7 +23,6 @@ package com.oracle.graal.replacements; import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; import static com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation.*; import sun.misc.*; @@ -33,7 +32,8 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.graph.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; @@ -105,7 +105,9 @@ for (Kind kind : new Kind[]{Kind.Int, Kind.Long, Kind.Object}) { Class javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); CompareAndSwapNode compareAndSwap = new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any()); b.push(Kind.Boolean.getStackKind(), b.append(compareAndSwap)); compareAndSwap.setStateAfter(b.createStateAfter()); @@ -115,7 +117,9 @@ if (getAndSetEnabled(arch)) { r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); AtomicReadAndWriteNode atomicReadWrite = new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()); b.push(kind.getStackKind(), b.append(atomicReadWrite)); atomicReadWrite.setStateAfter(b.createStateAfter()); @@ -124,7 +128,9 @@ }); if (kind != Kind.Object) { r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode delta) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); AtomicReadAndAddNode atomicReadAdd = new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any()); b.push(kind.getStackKind(), b.append(atomicReadAdd)); atomicReadAdd.setStateAfter(b.createStateAfter()); @@ -150,25 +156,25 @@ Class type = kind.toJavaClass(); Registration r = new Registration(plugins, declaringClass); r.register1("reverseBytes", type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null, value))); return true; } }); r.register1("bitCount", type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null, value))); return true; } }); r.register2("divideUnsigned", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); return true; } }); r.register2("remainderUnsigned", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); return true; } @@ -178,7 +184,7 @@ private static void registerCharacterPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Character.class); r.register1("reverseBytes", char.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { // return (char) (Integer.reverse(i) >> 16); ReverseBytesNode reverse = b.append(new ReverseBytesNode(value)); RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16)))); @@ -192,7 +198,7 @@ private static void registerShortPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Short.class); r.register1("reverseBytes", short.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { // return (short) (Integer.reverse(i) >> 16); ReverseBytesNode reverse = b.append(new ReverseBytesNode(value)); RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16)))); @@ -206,13 +212,13 @@ private static void registerFloatPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Float.class); r.register1("floatToRawIntBits", float.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Int, b.recursiveAppend(new ReinterpretNode(Kind.Int, value).canonical(null, value))); return true; } }); r.register1("intBitsToFloat", int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Float, b.recursiveAppend(new ReinterpretNode(Kind.Float, value).canonical(null, value))); return true; } @@ -222,13 +228,13 @@ private static void registerDoublePlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Double.class); r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Long, b.recursiveAppend(new ReinterpretNode(Kind.Long, value).canonical(null, value))); return true; } }); r.register1("longBitsToDouble", long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Double, b.recursiveAppend(new ReinterpretNode(Kind.Double, value).canonical(null, value))); return true; } @@ -238,32 +244,32 @@ private static void registerMathPlugins(Architecture arch, InvocationPlugins plugins) { Registration r = new Registration(plugins, Math.class); r.register1("abs", Float.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Float, b.recursiveAppend(new AbsNode(value).canonical(null, value))); return true; } }); r.register1("abs", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Double, b.recursiveAppend(new AbsNode(value).canonical(null, value))); return true; } }); r.register1("sqrt", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null, value))); return true; } }); if (getAndSetEnabled(arch)) { r.register1("log", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG))); return true; } }); r.register1("log10", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG10))); return true; } @@ -278,7 +284,7 @@ this.condition = condition; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { // the mirroring and negation operations get the condition into canonical form boolean mirror = condition.canonicalMirror(); boolean negate = condition.canonicalNegate(); @@ -312,25 +318,25 @@ r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE)); r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE)); r.register2("divide", int.class, int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(Kind.Int, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); return true; } }); r.register2("divide", long.class, long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(Kind.Long, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); return true; } }); r.register2("remainder", int.class, int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(Kind.Int, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); return true; } }); r.register2("remainder", long.class, long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(Kind.Long, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); return true; } @@ -349,7 +355,8 @@ private static void registerObjectPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Object.class); r.register1("", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode object = receiver.get(); if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) { RegisterFinalizerNode registerFinalizer = new RegisterFinalizerNode(object); b.append(registerFinalizer); @@ -363,24 +370,23 @@ private static void registerClassPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Class.class); r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) { - ValueNode nullCheckedType = nullCheckedValue(b, type); - LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object)); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) { + LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object)); b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null))); return true; } }); r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode otherType) { - ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType)); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) { + ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType)); b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null))); return true; } }); r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr, ValueNode object) { - if (rcvr.isConstant() && !rcvr.isNullConstant()) { - ResolvedJavaType type = b.getConstantReflection().asJavaType(rcvr.asConstant()); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { + if (receiver.isConstant() && !receiver.isNullConstant()) { + ResolvedJavaType type = b.getConstantReflection().asJavaType(receiver.get().asConstant()); if (type != null && !type.isPrimitive()) { b.push(Kind.Object, b.append(CheckCastNode.create(type, object, null, false, b.getAssumptions()))); return true; @@ -402,7 +408,7 @@ Registration r = new Registration(plugins, Edges.class); for (Class c : new Class[]{Node.class, NodeList.class}) { r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) { ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any())); boolean exactType = false; boolean nonNull = false; @@ -411,7 +417,7 @@ } }); r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) { UnsafeStoreNode unsafeStore = new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any()); b.append(unsafeStore); unsafeStore.setStateAfter(b.createStateAfter()); @@ -429,7 +435,7 @@ this.kind = kind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { if (b.parsingReplacement()) { ResolvedJavaMethod rootMethod = b.getRootMethod(); if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { @@ -456,7 +462,7 @@ this.kind = kind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { if (b.parsingReplacement()) { ResolvedJavaMethod rootMethod = b.getRootMethod(); if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { @@ -465,7 +471,7 @@ return false; } } - ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), nullCheckedValue(b, value), kind); + ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind); b.push(kind.getStackKind(), b.append(valueNode)); return true; } @@ -486,12 +492,16 @@ this.isVolatile = isVolatile; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); b.push(returnKind.getStackKind(), b.append(new DirectReadNode(address, returnKind))); return true; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_READ)); } @@ -513,12 +523,16 @@ this.isVolatile = isVolatile; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); b.append(new DirectStoreNode(address, value, kind)); return true; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE)); } @@ -535,42 +549,42 @@ private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, GraalDirectives.class); r.register0("deoptimize", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register0("deoptimizeAndInvalidate", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register0("inCompiledCode", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.push(Kind.Int, b.append(ConstantNode.forInt(1))); return true; } }); r.register0("controlFlowAnchor", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new ControlFlowAnchorNode()); return true; } }); r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) { b.push(Kind.Int, b.append(new BranchProbabilityNode(probability, condition))); return true; } }); InvocationPlugin blackholePlugin = new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.append(new BlackholeNode(value)); return true; } @@ -583,7 +597,7 @@ final Kind stackKind = kind.getStackKind(); r.register1("opaque", javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(stackKind, b.append(new OpaqueNode(value))); return true; } @@ -594,7 +608,8 @@ private static void registerJMHBlackholePlugins(InvocationPlugins plugins) { InvocationPlugin blackholePlugin = new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode blackhole, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) { + blackhole.get(); b.append(new BlackholeNode(value)); return true; } diff -r 71040f48cc34 -r 9b669776bf8a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Thu Mar 19 19:27:25 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Thu Mar 19 22:31:42 2015 +0100 @@ -32,7 +32,8 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -68,9 +69,9 @@ public static void registerOptimizedAssumptionPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, OptimizedAssumption.class); r.register1("isValid", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { - if (arg.isConstant()) { - Constant constant = arg.asConstant(); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + if (receiver.isConstant()) { + Constant constant = receiver.get().asConstant(); OptimizedAssumption assumption = b.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant); b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(assumption.isValid()))); if (assumption.isValid()) { @@ -89,31 +90,31 @@ for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) { Class type = kind.toJavaClass(); r.register2("addExact", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerAddExactNode(x, y))); return true; } }); r.register2("subtractExact", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerSubExactNode(x, y))); return true; } }); r.register2("multiplyExact", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerMulExactNode(x, y))); return true; } }); r.register2("multiplyHigh", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerMulHighNode(x, y))); return true; } }); r.register2("multiplyHighUnsigned", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new UnsignedMulHighNode(x, y))); return true; } @@ -124,47 +125,47 @@ public static void registerCompilerDirectivesPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, CompilerDirectives.class); r.register0("inInterpreter", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(false))); return true; } }); r.register0("inCompiledCode", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true))); return true; } }); r.register0("transferToInterpreter", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { return true; } }); r.register1("interpreterOnly", Callable.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { return true; } }); r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) { b.push(Kind.Boolean.getStackKind(), b.append(new BranchProbabilityNode(probability, condition))); return true; } }); r.register1("bailout", String.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) { if (message.isConstant()) { throw b.bailout(message.asConstant().toValueString()); } @@ -172,7 +173,7 @@ } }); r.register1("isCompilationConstant", Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) { b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true))); } else { @@ -182,7 +183,7 @@ } }); r.register1("materialize", Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.append(new ForceMaterializeNode(value)); return true; } @@ -190,7 +191,7 @@ r = new Registration(plugins, CompilerAsserts.class); r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ValueNode curValue = value; if (curValue instanceof BoxNode) { BoxNode boxNode = (BoxNode) curValue; @@ -215,7 +216,7 @@ } }); r.register1("neverPartOfCompilation", String.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) { if (message.isConstant()) { String messageString = message.asConstant().toValueString(); b.append(new NeverPartOfCompilationNode(messageString)); @@ -229,14 +230,14 @@ public static void registerOptimizedCallTargetPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) { Registration r = new Registration(plugins, OptimizedCallTarget.class); r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode descriptor, ValueNode args) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode descriptor, ValueNode args) { Class frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class; b.push(Kind.Object, b.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), descriptor, args))); return true; } }); r.register2("castArrayFixedLength", Object[].class, int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode args, ValueNode length) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode args, ValueNode length) { b.push(Kind.Object, b.append(new PiArrayNode(args, length, args.stamp()))); return true; } @@ -264,8 +265,8 @@ private static void registerMaterialize(Registration r) { r.register1("materialize", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode frame) { - b.push(Kind.Object, b.append(new MaterializeFrameNode(GraphBuilderContext.nullCheckedValue(b, frame)))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver frame) { + b.push(Kind.Object, b.append(new MaterializeFrameNode(frame.get()))); return true; } }); @@ -273,7 +274,7 @@ private static void registerUnsafeCast(Registration r) { r.register4("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) { if (clazz.isConstant() && nonNull.isConstant()) { ConstantReflectionProvider constantReflection = b.getConstantReflection(); ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant()); @@ -331,7 +332,7 @@ this.returnKind = returnKind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) { if (location.isConstant()) { LocationIdentity locationIdentity; if (location.isNullConstant()) { @@ -356,7 +357,7 @@ this.kind = kind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) { ValueNode locationArgument = location; if (locationArgument.isConstant()) { LocationIdentity locationIdentity;