changeset 20045:8470e81631f8

converted all @MacroSubstitution uses to InvocationPlugins
author Doug Simon <doug.simon@oracle.com>
date Fri, 27 Mar 2015 13:29:08 +0100
parents c1f116cd4b67
children 116c600253e5
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassQueryNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedAssumptionSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java
diffstat 53 files changed, 797 insertions(+), 1362 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri Mar 27 13:29:08 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -62,6 +63,8 @@
     /**
      * Raw operation for adding a node to the graph when neither {@link #add},
      * {@link #addPush(ValueNode)} nor {@link #addPush(Kind, ValueNode)} can be used.
+     *
+     * @return either the node added or an equivalent node
      */
     <T extends ValueNode> T append(T value);
 
@@ -85,28 +88,31 @@
     void push(Kind kind, ValueNode value);
 
     /**
-     * Appends a node with a void kind to the graph. If the returned node is a {@link StateSplit},
-     * with a null {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
+     * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null
+     * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
      *
      * @param value the value to add to the graph and push to the stack. The {@code value.getKind()}
      *            kind is used when type checking this operation.
      * @return a node equivalent to {@code value} in the graph
      */
     default <T extends ValueNode> T add(T value) {
-        assert value.getKind() == Kind.Void;
-        T appended = append(value);
-        if (appended instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) appended;
+        if (value.graph() != null) {
+            assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
+            return value;
+        }
+        T equivalentValue = append(value);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
             if (stateSplit.stateAfter() == null) {
                 stateSplit.setStateAfter(createStateAfter());
             }
         }
-        return appended;
+        return equivalentValue;
     }
 
     /**
      * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
-     * is a {@link StateSplit}, with a null {@linkplain StateSplit#stateAfter() frame state}, the
+     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
      * frame state is initialized.
      *
      * @param value the value to add to the graph and push to the stack. The {@code value.getKind()}
@@ -119,7 +125,7 @@
 
     /**
      * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
-     * is a {@link StateSplit}, with a null {@linkplain StateSplit#stateAfter() frame state}, the
+     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
      * frame state is initialized.
      *
      * @param kind the kind to use when type checking this operation
@@ -127,17 +133,28 @@
      * @return a node equivalent to {@code value} in the graph
      */
     default <T extends ValueNode> T addPush(Kind kind, T value) {
-        T appended = append(value);
-        push(kind, appended);
-        if (appended instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) appended;
+        T equivalentValue = value.graph() != null ? value : append(value);
+        push(kind.getStackKind(), equivalentValue);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
             if (stateSplit.stateAfter() == null) {
                 stateSplit.setStateAfter(createStateAfter());
             }
         }
-        return appended;
+        return equivalentValue;
     }
 
+    /**
+     * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
+     * one for which the plugin was applied). This applies all standard graph builder processing to
+     * the replaced invocation including applying any relevant plugins to it.
+     *
+     * @param invokeKind the kind of the replacement invocation
+     * @param targetMethod the target of the replacement invocation
+     * @param args the arguments to the replacement invocation
+     */
+    void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args);
+
     StampProvider getStampProvider();
 
     MetaAccessProvider getMetaAccess();
@@ -177,6 +194,16 @@
     int bci();
 
     /**
+     * Gets the kind of invocation currently being parsed.
+     */
+    InvokeKind getInvokeKind();
+
+    /**
+     * Gets the return type of the invocation currently being parsed.
+     */
+    JavaType getInvokeReturnType();
+
+    /**
      * Gets the inline depth of this context. 0 implies this is the context for the
      * {@linkplain #getRootMethod() root method}.
      */
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Fri Mar 27 13:29:08 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.graphbuilderconf;
 
+import java.lang.invoke.*;
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.meta.*;
@@ -35,45 +36,65 @@
 public interface InvocationPlugin extends GraphBuilderPlugin {
 
     /**
+     * Determines if this plugin is for a method with a polymorphic signature (e.g.
+     * {@link MethodHandle#invokeExact(Object...)}).
+     */
+    default boolean isSignaturePolymorphic() {
+        return false;
+    }
+
+    /**
+     * Handles invocation of a signature polymorphic method.
+     *
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in
+     *            position 0 if {@code targetMethod} is not static
+     * @see #execute
+     */
+    default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) {
+        return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+    }
+
+    /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-        throw invalidHandler(b, targetMethod, receiver);
+        return defaultHandler(b, targetMethod, receiver);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
-        throw invalidHandler(b, targetMethod, receiver, arg);
+        return defaultHandler(b, targetMethod, receiver, arg);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
-        throw invalidHandler(b, targetMethod, receiver, arg1, arg2);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3);
     }
 
     /**
      * @see #execute
      */
     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);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
     }
 
     /**
      * @see #execute
      */
     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);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
     }
 
     default ResolvedJavaMethod getSubstitute() {
@@ -82,56 +103,64 @@
 
     /**
      * Executes a given plugin against a set of invocation arguments by dispatching to the
-     * {@code apply(...)} method that matches the number of arguments.
+     * {@code apply(...)} method that matches the number of arguments or to
+     * {@link #applyPolymorphic} if {@code plugin} is {@linkplain #isSignaturePolymorphic()
+     * signature polymorphic}.
      *
      * @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
+     * @param argsIncludingReceiver all arguments to the invocation include the receiver in position
+     *            0 if {@code targetMethod} is not static
      * @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, Receiver receiver, ValueNode[] args) {
-        if (receiver != null) {
+    static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, Receiver receiver, ValueNode[] argsIncludingReceiver) {
+        if (plugin.isSignaturePolymorphic()) {
+            return plugin.applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver);
+        } else if (receiver != null) {
             assert !targetMethod.isStatic();
-            assert args.length > 0;
-            if (args.length == 1) {
+            assert argsIncludingReceiver.length > 0;
+            if (argsIncludingReceiver.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 if (argsIncludingReceiver.length == 2) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
             } else {
-                throw plugin.invalidHandler(b, targetMethod, receiver, args);
+                return plugin.defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
             }
         } else {
             assert targetMethod.isStatic();
-            if (args.length == 0) {
+            if (argsIncludingReceiver.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 if (argsIncludingReceiver.length == 1) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0]);
+            } else if (argsIncludingReceiver.length == 2) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
             } else {
-                throw plugin.invalidHandler(b, targetMethod, receiver, args);
+                return plugin.defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
             }
 
         }
     }
 
-    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);
+    /**
+     * Handles an invocation when a specific {@code apply} method is not available.
+     */
+    default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") Receiver receiver, ValueNode... args) {
+        throw new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
     }
 
     default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
@@ -139,8 +168,10 @@
         for (Method m : c.getDeclaredMethods()) {
             if (m.getName().equals("apply")) {
                 return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            } else if (m.getName().equals("defaultHandler")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
             }
         }
-        throw new GraalInternalError("could not find method named \"apply\" in " + c.getName());
+        throw new GraalInternalError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName());
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Mar 27 13:29:08 2015 +0100
@@ -28,10 +28,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 
@@ -81,21 +79,4 @@
         }
         return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
-
-    @Override
-    public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        int intrinsicId = hsMethod.intrinsicId();
-        if (intrinsicId != 0) {
-            /*
-             * The methods of MethodHandle that need substitution are signature-polymorphic, i.e.,
-             * the VM replicates them for every signature that they are actually used for.
-             * Therefore, we cannot use the usual annotation-driven mechanism to define the
-             */
-            if (MethodHandleNode.lookupMethodHandleIntrinsic(method, providers.getConstantReflection().getMethodHandleAccess()) != null) {
-                return MethodHandleNode.class;
-            }
-        }
-        return super.getMacroSubstitution(method);
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Mar 27 13:29:08 2015 +0100
@@ -24,6 +24,10 @@
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
+import java.lang.invoke.*;
+
+import sun.reflect.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -35,7 +39,9 @@
 import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.ClassQueryNode.Query;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
@@ -60,7 +66,7 @@
      */
     public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
                     SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements, Architecture arch) {
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, constantReflection.getMethodHandleAccess());
 
         Plugins plugins = new Plugins(invocationPlugins);
         NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
@@ -73,8 +79,11 @@
         plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin));
 
         registerObjectPlugins(invocationPlugins);
+        registerClassPlugins(invocationPlugins);
         registerSystemPlugins(invocationPlugins, foreignCalls);
         registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
+        registerCallSitePlugins(invocationPlugins);
+        registerReflectionPlugins(invocationPlugins);
         registerStableOptionPlugins(invocationPlugins);
         StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, arch, invocationPlugins, !config.useHeapProfiler);
 
@@ -89,13 +98,79 @@
                 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()));
+                    mirror = ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess());
                 } else {
                     StampProvider stampProvider = b.getStampProvider();
-                    LoadHubNode hub = b.append(new LoadHubNode(stampProvider, rcvr));
-                    mirror = b.append(new HubGetClassNode(b.getMetaAccess(), hub));
+                    LoadHubNode hub = b.add(new LoadHubNode(stampProvider, rcvr));
+                    mirror = new HubGetClassNode(b.getMetaAccess(), hub);
+                }
+                b.addPush(Kind.Object, mirror);
+                return true;
+            }
+        });
+        r.register1("clone", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode object = receiver.get();
+                b.addPush(Kind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
+                return true;
+            }
+        });
+    }
+
+    private static void registerClassPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Class.class);
+
+        for (Query query : Query.values()) {
+            r.register1(query.name(), Receiver.class, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                    ValueNode javaClass = receiver.get();
+                    ValueNode folded = ClassQueryNode.tryFold(javaClass, query, b.getMetaAccess(), b.getConstantReflection());
+                    if (folded != null) {
+                        b.addPush(query.returnKind, folded);
+                    } else {
+                        b.addPush(query.returnKind, new ClassQueryNode(b.getInvokeKind(), targetMethod, query, b.bci(), b.getInvokeReturnType(), javaClass));
+                    }
+                    return true;
                 }
-                b.push(Kind.Object, mirror);
+            });
+        }
+        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                ValueNode javaClass = receiver.get();
+                ValueNode folded = ClassCastNode.tryFold(javaClass, object, b.getConstantReflection(), b.getAssumptions());
+                if (folded != null) {
+                    b.addPush(Kind.Object, folded);
+                } else {
+                    b.addPush(Kind.Object, new ClassCastNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), javaClass, object));
+                }
+                return true;
+            }
+        });
+    }
+
+    private static void registerCallSitePlugins(InvocationPlugins plugins) {
+        InvocationPlugin plugin = new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode callSite = receiver.get();
+                ValueNode folded = CallSiteTargetNode.tryFold(callSite, b.getMetaAccess(), b.getAssumptions());
+                if (folded != null) {
+                    b.addPush(Kind.Object, folded);
+                } else {
+                    b.addPush(Kind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), callSite));
+                }
+                return true;
+            }
+        };
+        plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
+        plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
+        plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
+    }
+
+    private static void registerReflectionPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Reflection.class);
+        r.register0("getCallerClass", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.addPush(new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType()));
                 return true;
             }
         });
@@ -115,14 +190,26 @@
                 return true;
             }
         });
+        r.register1("identityHashCode", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.addPush(new SystemIdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
+                return true;
+            }
+        });
+        r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+                b.add(new ArrayCopyNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), src, srcPos, dst, dstPos, length));
+                return true;
+            }
+        });
     }
 
     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, Receiver receiver) {
-                CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind()));
-                ConstantLocationNode location = b.append(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset));
+                CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
+                ConstantLocationNode location = b.add(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset));
                 boolean compressible = false;
                 ValueNode javaThread = WordOperationPlugin.readOp(b, Kind.Object, thread, location, BarrierType.NONE, compressible);
                 boolean exactType = compressible;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Fri Mar 27 13:29:08 2015 +0100
@@ -22,14 +22,22 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.meta.HotSpotMethodHandleAccessProvider.*;
+
+import java.lang.invoke.*;
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.phases.*;
+import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
 
 /**
@@ -37,10 +45,12 @@
  */
 final class HotSpotInvocationPlugins extends InvocationPlugins {
     final HotSpotVMConfig config;
+    final MethodHandleAccessProvider methodHandleAccess;
 
-    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, MethodHandleAccessProvider methodHandleAccess) {
         super(metaAccess);
         this.config = config;
+        this.methodHandleAccess = methodHandleAccess;
     }
 
     @Override
@@ -74,6 +84,62 @@
         super.register(plugin, declaringClass, name, argumentTypes);
     }
 
+    private ResolvedJavaType methodHandleClass;
+    private final Map<IntrinsicMethod, InvocationPlugin> methodHandlePlugins = new EnumMap<>(IntrinsicMethod.class);
+
+    @Override
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        if (methodHandleClass == null) {
+            methodHandleClass = metaAccess.lookupJavaType(MethodHandle.class);
+        }
+        if (method.getDeclaringClass().equals(methodHandleClass)) {
+            HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+            int intrinsicId = hsMethod.intrinsicId();
+            if (intrinsicId != 0) {
+                /*
+                 * The methods of MethodHandle that need substitution are signature-polymorphic,
+                 * i.e., the VM replicates them for every signature that they are actually used for.
+                 */
+                IntrinsicMethod intrinsicMethod = getMethodHandleIntrinsic(intrinsicId);
+                if (intrinsicMethod != null) {
+                    InvocationPlugin plugin = methodHandlePlugins.get(intrinsicMethod);
+                    if (plugin == null) {
+                        plugin = new InvocationPlugin() {
+                            public boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) {
+                                InvokeKind invokeKind = b.getInvokeKind();
+                                if (invokeKind != InvokeKind.Static) {
+                                    receiver.get();
+                                }
+                                InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, targetMethod,
+                                                b.bci(), b.getInvokeReturnType(), argsIncludingReceiver);
+                                if (invoke == null) {
+                                    b.addPush(new MethodHandleNode(intrinsicMethod, invokeKind, targetMethod, b.bci(), b.getInvokeReturnType(), argsIncludingReceiver));
+                                } else {
+                                    CallTargetNode callTarget = invoke.callTarget();
+                                    NodeInputList<ValueNode> argumentsList = callTarget.arguments();
+                                    ValueNode[] args = argumentsList.toArray(new ValueNode[argumentsList.size()]);
+                                    for (ValueNode arg : args) {
+                                        b.recursiveAppend(arg);
+                                    }
+                                    b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), args);
+                                }
+                                return true;
+                            }
+
+                            public boolean isSignaturePolymorphic() {
+                                return true;
+                            }
+                        };
+                        methodHandlePlugins.put(intrinsicMethod, plugin);
+                    }
+                    return plugin;
+                }
+            }
+
+        }
+        return super.lookupInvocation(method);
+    }
+
     @Override
     public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
         if (GraalOptions.ImmutableCode.getValue()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java	Fri Mar 27 13:29:08 2015 +0100
@@ -98,18 +98,23 @@
     public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
         int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId();
         if (intrinsicId != 0) {
-            HotSpotVMConfig config = runtime().getConfig();
-            if (intrinsicId == config.vmIntrinsicInvokeBasic) {
-                return IntrinsicMethod.INVOKE_BASIC;
-            } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
-                return IntrinsicMethod.LINK_TO_INTERFACE;
-            } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
-                return IntrinsicMethod.LINK_TO_SPECIAL;
-            } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
-                return IntrinsicMethod.LINK_TO_STATIC;
-            } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
-                return IntrinsicMethod.LINK_TO_VIRTUAL;
-            }
+            return getMethodHandleIntrinsic(intrinsicId);
+        }
+        return null;
+    }
+
+    public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) {
+        HotSpotVMConfig config = runtime().getConfig();
+        if (intrinsicId == config.vmIntrinsicInvokeBasic) {
+            return IntrinsicMethod.INVOKE_BASIC;
+        } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
+            return IntrinsicMethod.LINK_TO_INTERFACE;
+        } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
+            return IntrinsicMethod.LINK_TO_SPECIAL;
+        } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
+            return IntrinsicMethod.LINK_TO_STATIC;
+        } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
+            return IntrinsicMethod.LINK_TO_VIRTUAL;
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Fri Mar 27 13:29:08 2015 +0100
@@ -79,9 +79,9 @@
                 assert right.stamp() instanceof MetaspacePointerStamp : right + " " + right.stamp();
                 assert opcode == POINTER_EQ || opcode == POINTER_NE;
 
-                PointerEqualsNode comparison = b.append(new PointerEqualsNode(left, right));
-                ValueNode eqValue = b.append(forBoolean(opcode == POINTER_EQ));
-                ValueNode neValue = b.append(forBoolean(opcode == POINTER_NE));
+                PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right));
+                ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ));
+                ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE));
                 b.addPush(returnStackKind, new ConditionalNode(comparison, eqValue, neValue));
                 break;
 
@@ -90,8 +90,8 @@
                 ValueNode pointer = args[0];
                 assert pointer.stamp() instanceof MetaspacePointerStamp;
 
-                IsNullNode isNull = b.append(new IsNullNode(pointer));
-                b.addPush(returnStackKind, new ConditionalNode(isNull, b.append(forBoolean(true)), b.append(forBoolean(false))));
+                IsNullNode isNull = b.add(new IsNullNode(pointer));
+                b.addPush(returnStackKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
                 break;
 
             case FROM_POINTER:
@@ -118,7 +118,7 @@
                 } else {
                     location = makeLocation(b, args[1], args[2]);
                 }
-                ReadNode read = b.append(new ReadNode(args[0], location, readStamp, BarrierType.NONE));
+                ReadNode read = b.add(new ReadNode(args[0], location, readStamp, BarrierType.NONE));
                 /*
                  * The read must not float outside its block otherwise it may float above an
                  * explicit zero check on its base address.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -25,24 +25,23 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 /**
  * {@link MacroNode Macro node} for {@link Class#cast(Object)}.
- *
- * @see HotSpotClassSubstitutions#cast(Class, Object)
  */
 @NodeInfo
 public final class ClassCastNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
     public static final NodeClass<ClassCastNode> TYPE = NodeClass.create(ClassCastNode.class);
 
-    public ClassCastNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ClassCastNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode receiver, ValueNode object) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver, object);
     }
 
     private ValueNode getJavaClass() {
@@ -63,12 +62,18 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forJavaClass, ValueNode forObject) {
-        if (forJavaClass.isConstant()) {
-            ResolvedJavaType type = tool.getConstantReflection().asJavaType(forJavaClass.asConstant());
+        ValueNode folded = tryFold(forJavaClass, forObject, tool.getConstantReflection(), null);
+        return folded != null ? folded : this;
+    }
+
+    public static ValueNode tryFold(ValueNode javaClass, ValueNode object, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
+        ValueNode value = GraphUtil.originalValue(javaClass);
+        if (value.isConstant()) {
+            ResolvedJavaType type = constantReflection.asJavaType(value.asConstant());
             if (type != null && !type.isPrimitive()) {
-                return new CheckCastNode(type, forObject, null, false);
+                return CheckCastNode.create(type, object, null, false, assumptions);
             }
         }
-        return this;
+        return null;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getClassLoader0()}.
- *
- * @see HotSpotClassSubstitutions#getClassLoader0(Class)
- */
-@SuppressWarnings("javadoc")
-@NodeInfo
-public final class ClassGetClassLoader0Node extends MacroStateSplitNode implements Canonicalizable {
-
-    public static final NodeClass<ClassGetClassLoader0Node> TYPE = NodeClass.create(ClassGetClassLoader0Node.class);
-
-    public ClassGetClassLoader0Node(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant() && !GraalOptions.ImmutableCode.getValue()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
-            JavaConstant classLoader = c.getClassLoader();
-            if (classLoader != null) {
-                return ConstantNode.forConstant(classLoader, tool.getMetaAccess());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getComponentType()}.
- *
- * @see HotSpotClassSubstitutions#getComponentType(Class)
- */
-@NodeInfo
-public final class ClassGetComponentTypeNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassGetComponentTypeNode> TYPE = NodeClass.create(ClassGetComponentTypeNode.class);
-
-    public ClassGetComponentTypeNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
-            JavaConstant componentType = c.getComponentType();
-            if (componentType != null) {
-                return ConstantNode.forConstant(componentType, tool.getMetaAccess());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getModifiers()}.
- *
- * @see HotSpotClassSubstitutions#getModifiers(Class)
- */
-@NodeInfo
-public final class ClassGetModifiersNode extends MacroNode implements Canonicalizable {
-    public static final NodeClass<ClassGetModifiersNode> TYPE = NodeClass.create(ClassGetModifiersNode.class);
-
-    public ClassGetModifiersNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forInt(type.getModifiers());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getSuperclass()}.
- *
- * @see HotSpotClassSubstitutions#getSuperclass(Class)
- */
-@NodeInfo
-public final class ClassGetSuperclassNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassGetSuperclassNode> TYPE = NodeClass.create(ClassGetSuperclassNode.class);
-
-    public ClassGetSuperclassNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
-            JavaConstant superclass = c.getSuperclass();
-            if (superclass != null) {
-                return ConstantNode.forConstant(superclass, tool.getMetaAccess());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isArray()}.
- *
- * @see HotSpotClassSubstitutions#isArray(Class)
- */
-@NodeInfo
-public final class ClassIsArrayNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassIsArrayNode> TYPE = NodeClass.create(ClassIsArrayNode.class);
-
-    public ClassIsArrayNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forBoolean(type.isArray());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isInterface()}.
- *
- * @see HotSpotClassSubstitutions#isInterface(Class)
- */
-@NodeInfo
-public final class ClassIsInterfaceNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassIsInterfaceNode> TYPE = NodeClass.create(ClassIsInterfaceNode.class);
-
-    public ClassIsInterfaceNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forBoolean(type.isInterface());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isPrimitive()}.
- *
- * @see HotSpotClassSubstitutions#isPrimitive(Class)
- */
-@NodeInfo
-public final class ClassIsPrimitiveNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassIsPrimitiveNode> TYPE = NodeClass.create(ClassIsPrimitiveNode.class);
-
-    public ClassIsPrimitiveNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forBoolean(type.isPrimitive());
-            }
-        }
-        return this;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassQueryNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * {@link MacroNode Macro node} for some basic query methods in {@link Class}.
+ */
+@NodeInfo
+public final class ClassQueryNode extends MacroStateSplitNode implements Canonicalizable {
+
+    /**
+     * The query methods in {@link Class} supported by {@link ClassQueryNode}.
+     */
+    public enum Query {
+        getClassLoader0(Kind.Object),
+        getComponentType(Kind.Object),
+        getSuperclass(Kind.Object),
+        getModifiers(Kind.Int),
+        isArray(Kind.Boolean),
+        isInterface(Kind.Boolean),
+        isPrimitive(Kind.Boolean);
+
+        private Query(Kind returnKind) {
+            this.returnKind = returnKind;
+        }
+
+        public final Kind returnKind;
+    }
+
+    public static final NodeClass<ClassQueryNode> TYPE = NodeClass.create(ClassQueryNode.class);
+
+    protected final Query query;
+
+    public ClassQueryNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, Query query, int bci, JavaType returnType, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver);
+        this.query = query;
+        assert query.returnKind == targetMethod.getSignature().getReturnKind();
+    }
+
+    private ValueNode getJavaClass() {
+        return arguments.get(0);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode value = tryFold(getJavaClass(), query, tool.getMetaAccess(), tool.getConstantReflection());
+        return value == null ? this : value;
+    }
+
+    public static ValueNode tryFold(ValueNode javaClass, Query query, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        ValueNode value = GraphUtil.originalValue(javaClass);
+        if (value != null && value.isConstant()) {
+            if (query.returnKind == Kind.Object) {
+                if (GraalOptions.ImmutableCode.getValue()) {
+                    return null;
+                }
+                HotSpotObjectConstant c = (HotSpotObjectConstant) value.asConstant();
+                JavaConstant answer;
+                switch (query) {
+                    case getClassLoader0:
+                        answer = c.getClassLoader();
+                        break;
+                    case getComponentType:
+                        answer = c.getComponentType();
+                        break;
+                    case getSuperclass:
+                        answer = c.getSuperclass();
+                        break;
+                    default:
+                        GraalInternalError.shouldNotReachHere();
+                        answer = null;
+                }
+                if (answer != null) {
+                    return ConstantNode.forConstant(answer, metaAccess);
+                }
+            } else {
+                ResolvedJavaType type = constantReflection.asJavaType(value.asConstant());
+                if (type != null) {
+                    switch (query) {
+                        case isArray:
+                            return ConstantNode.forBoolean(type.isArray());
+                        case isPrimitive:
+                            return ConstantNode.forBoolean(type.isPrimitive());
+                        case isInterface:
+                            return ConstantNode.forBoolean(type.isInterface());
+                        case getModifiers:
+                            return ConstantNode.forInt(type.getModifiers());
+                        default:
+                            GraalInternalError.shouldNotReachHere();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A call target that replaces itself in the graph when being lowered by restoring the original
+ * {@link MethodHandle} invocation target. This is required for when a {@link MethodHandle} call was
+ * resolved to a constant target but the target was not inlined. In that case, the original
+ * invocation must be restored with all of its original arguments. Why? HotSpot linkage for
+ * {@link MethodHandle} intrinsics (see {@code MethodHandles::generate_method_handle_dispatch})
+ * expects certain implicit arguments to be on the stack such as the MemberName suffix argument for
+ * a call to one of the MethodHandle.linkTo* methods. An
+ * {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} invocation
+ * drops these arguments which means the interpreter won't find them.
+ */
+@NodeInfo
+public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
+
+    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
+    protected final ResolvedJavaMethod originalTargetMethod;
+    protected final JavaType originalReturnType;
+    @Input NodeInputList<ValueNode> originalArguments;
+
+    public ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, JavaType originalReturnType) {
+        super(TYPE, invokeKind, targetMethod, arguments, returnType);
+        this.originalTargetMethod = originalTargetMethod;
+        this.originalReturnType = originalReturnType;
+        this.originalArguments = new NodeInputList<>(this, originalArguments);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        MethodCallTargetNode replacement = graph().add(
+                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType));
+
+        // Replace myself...
+        this.replaceAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.nodes.spi.*;
-
-@ServiceProvider(ReplacementsProvider.class)
-public class CallSiteSubstitutions implements ReplacementsProvider {
-
-    @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
-        replacements.registerSubstitutions(ConstantCallSite.class, ConstantCallSiteSubstitutions.class);
-        replacements.registerSubstitutions(MutableCallSite.class, MutableCallSiteSubstitutions.class);
-        replacements.registerSubstitutions(VolatileCallSite.class, VolatileCallSiteSubstitutions.class);
-    }
-
-    @ClassSubstitution(ConstantCallSite.class)
-    private static class ConstantCallSiteSubstitutions {
-
-        @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class)
-        public static native MethodHandle getTarget(ConstantCallSite callSite);
-    }
-
-    @ClassSubstitution(MutableCallSite.class)
-    private static class MutableCallSiteSubstitutions {
-
-        @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class)
-        public static native MethodHandle getTarget(MutableCallSite callSite);
-    }
-
-    @ClassSubstitution(VolatileCallSite.class)
-    private static class VolatileCallSiteSubstitutions {
-
-        @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class)
-        public static native MethodHandle getTarget(VolatileCallSite callSite);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -27,8 +27,10 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -36,18 +38,19 @@
 
     public static final NodeClass<CallSiteTargetNode> TYPE = NodeClass.create(CallSiteTargetNode.class);
 
-    public CallSiteTargetNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public CallSiteTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver);
     }
 
     private ValueNode getCallSite() {
         return arguments.get(0);
     }
 
-    private ConstantNode getConstantCallTarget(MetaAccessProvider metaAccess) {
-        if (getCallSite().isConstant() && !getCallSite().isNullConstant()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) getCallSite().asConstant();
-            JavaConstant target = c.getCallSiteTarget(graph().getAssumptions());
+    public static ConstantNode tryFold(ValueNode initialCallSite, MetaAccessProvider metaAccess, Assumptions assumptions) {
+        ValueNode callSite = GraphUtil.originalValue(initialCallSite);
+        if (callSite.isConstant() && !callSite.isNullConstant()) {
+            HotSpotObjectConstant c = (HotSpotObjectConstant) callSite.asConstant();
+            JavaConstant target = c.getCallSiteTarget(assumptions);
             if (target != null) {
                 return ConstantNode.forConstant(target, metaAccess);
             }
@@ -57,7 +60,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ConstantNode target = getConstantCallTarget(tool.getMetaAccess());
+        ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions());
         if (target != null) {
             return target;
         }
@@ -67,7 +70,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        ConstantNode target = getConstantCallTarget(tool.getMetaAccess());
+        ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions());
 
         if (target != null) {
             graph().replaceFixedWithFloating(this, target);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Fri Mar 27 13:29:08 2015 +0100
@@ -27,10 +27,8 @@
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +37,6 @@
 @ClassSubstitution(java.lang.Class.class)
 public class HotSpotClassSubstitutions {
 
-    @MacroSubstitution(macro = ClassGetModifiersNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static int getModifiers(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -51,8 +48,6 @@
         }
     }
 
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsInterfaceNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isInterface(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -64,8 +59,6 @@
         }
     }
 
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsArrayNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isArray(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -76,18 +69,14 @@
         }
     }
 
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsPrimitiveNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isPrimitive(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
         return klass.isNull();
     }
 
-    @MacroSubstitution(macro = ClassGetClassLoader0Node.class, isStatic = false)
     public static native ClassLoader getClassLoader0(Class<?> thisObj);
 
-    @MacroSubstitution(macro = ClassGetSuperclassNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getSuperclass(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -113,7 +102,6 @@
         return PiNode.asNonNullClass(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION));
     }
 
-    @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getComponentType(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -124,7 +112,4 @@
         }
         return null;
     }
-
-    @MacroSubstitution(macro = ClassCastNode.class, isStatic = false)
-    public static native Object cast(final Class<?> thisObj, Object obj);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
@@ -47,52 +48,50 @@
 public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
     public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
 
-    // Replacement method data
-    protected ResolvedJavaMethod replacementTargetMethod;
-    protected JavaType replacementReturnType;
-    @Input NodeInputList<ValueNode> replacementArguments;
+    protected final IntrinsicMethod intrinsicMethod;
 
-    public MethodHandleNode(Invoke invoke) {
-        super(TYPE, invoke);
-        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-        // See if we need to save some replacement method data.
-        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
-            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
-            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
-            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
-            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
-        } else {
-            // NodeInputList can't be null.
-            replacementArguments = new NodeInputList<>(this);
-        }
+    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
+        this.intrinsicMethod = intrinsicMethod;
     }
 
     /**
-     * Returns the method handle method intrinsic identifier for the provided method, or
-     * {@code null} if the method is not a method that can be handled by this class.
+     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
+     * invocation on another method with possibly transformed arguments.
+     *
+     * @param assumptions object for recording any speculations made during the transformation
+     * @param methodHandleAccess objects for accessing the implementation internals of a
+     *            {@link MethodHandle}
+     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
+     * @param bci the BCI of the original {@link MethodHandle} call
+     * @param returnType return type of the original {@link MethodHandle} call
+     * @param arguments arguments to the original {@link MethodHandle} call
+     * @return a more direct invocation derived from the {@link MethodHandle} call or null
      */
-    public static IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method, MethodHandleAccessProvider methodHandleAccess) {
-        return methodHandleAccess.lookupMethodHandleIntrinsic(method);
+    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode... arguments) {
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
     }
 
     @Override
     public void simplify(SimplifierTool tool) {
-        InvokeNode invoke;
-        IntrinsicMethod intrinsicMethod = lookupMethodHandleIntrinsic(targetMethod, tool.getConstantReflection().getMethodHandleAccess());
-        switch (intrinsicMethod) {
-            case INVOKE_BASIC:
-                invoke = getInvokeBasicTarget(tool, intrinsicMethod);
-                break;
-            case LINK_TO_STATIC:
-            case LINK_TO_SPECIAL:
-            case LINK_TO_VIRTUAL:
-            case LINK_TO_INTERFACE:
-                invoke = getLinkToTarget(tool, intrinsicMethod);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
+        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
+        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
+        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray);
         if (invoke != null) {
+            assert invoke.graph() == null;
+            invoke = graph().addOrUniqueWithInputs(invoke);
+            invoke.setStateAfter(stateAfter());
             FixedNode currentNext = next();
             replaceAtUsages(invoke);
             GraphUtil.removeFixedWithUnusedInputs(this);
@@ -105,8 +104,8 @@
      *
      * @return the receiver argument node
      */
-    private ValueNode getReceiver() {
-        return arguments.first();
+    private static ValueNode getReceiver(ValueNode[] arguments) {
+        return arguments[0];
     }
 
     /**
@@ -114,8 +113,8 @@
      *
      * @return the MemberName argument node (which is the last argument)
      */
-    private ValueNode getMemberName() {
-        return arguments.last();
+    private static ValueNode getMemberName(ValueNode[] arguments) {
+        return arguments[arguments.length - 1];
     }
 
     /**
@@ -124,10 +123,11 @@
      *
      * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
      */
-    protected InvokeNode getInvokeBasicTarget(SimplifierTool tool, IntrinsicMethod intrinsicMethod) {
-        ValueNode methodHandleNode = getReceiver();
+    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode methodHandleNode = getReceiver(arguments);
         if (methodHandleNode.isConstant()) {
-            return getTargetInvokeNode(tool.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), false), intrinsicMethod);
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
         }
         return null;
     }
@@ -140,10 +140,11 @@
      *
      * @return invoke node for the member name target
      */
-    protected InvokeNode getLinkToTarget(SimplifierTool tool, IntrinsicMethod intrinsicMethod) {
-        ValueNode memberNameNode = getMemberName();
+    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode memberNameNode = getMemberName(arguments);
         if (memberNameNode.isConstant()) {
-            return getTargetInvokeNode(tool.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant()), intrinsicMethod);
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
         }
         return null;
     }
@@ -155,7 +156,8 @@
      * @param target the target, already loaded from the member name node
      * @return invoke node for the member name target
      */
-    private InvokeNode getTargetInvokeNode(ResolvedJavaMethod target, IntrinsicMethod intrinsicMethod) {
+    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target,
+                    ResolvedJavaMethod original) {
         if (target == null) {
             return null;
         }
@@ -171,34 +173,35 @@
         // Cast receiver to its type.
         if (!isStatic) {
             JavaType receiverType = target.getDeclaringClass();
-            maybeCastArgument(0, receiverType);
+            maybeCastArgument(arguments, 0, receiverType);
         }
 
         // Cast reference arguments to its type.
         for (int index = 0; index < signature.getParameterCount(false); index++) {
             JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
-            maybeCastArgument(receiverSkip + index, parameterType);
+            maybeCastArgument(arguments, receiverSkip + index, parameterType);
         }
 
         if (target.canBeStaticallyBound()) {
-            return createTargetInvokeNode(target, intrinsicMethod);
+            return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments);
         }
 
         // Try to get the most accurate receiver type
         if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
-            ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
+            ValueNode receiver = getReceiver(arguments);
+            ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp());
             if (receiverType != null) {
                 AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
                 if (concreteMethod != null) {
-                    graph().getAssumptions().record(concreteMethod);
-                    return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
+                    assumptions.record(concreteMethod);
+                    return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
                 }
             }
         } else {
             AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
             if (concreteMethod != null) {
-                graph().getAssumptions().record(concreteMethod);
-                return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
+                assumptions.record(concreteMethod);
+                return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
             }
         }
 
@@ -212,15 +215,15 @@
      * @param index of the argument to be cast
      * @param type the type the argument should be cast to
      */
-    private void maybeCastArgument(int index, JavaType type) {
+    private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) {
         if (type instanceof ResolvedJavaType) {
             ResolvedJavaType targetType = (ResolvedJavaType) type;
             if (!targetType.isPrimitive()) {
-                ValueNode argument = arguments.get(index);
+                ValueNode argument = arguments[index];
                 ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
                 if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
-                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
-                    arguments.set(index, piNode);
+                    PiNode piNode = new PiNode(argument, StampFactory.declared(targetType));
+                    arguments[index] = piNode;
                 }
             }
         }
@@ -228,57 +231,42 @@
 
     /**
      * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
-     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
+     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
      *
-     * @param target the method to be called
      * @return invoke node for the member name target
      */
-    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod target, IntrinsicMethod intrinsicMethod) {
+    private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) {
         InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
         JavaType targetReturnType = target.getSignature().getReturnType(null);
 
         // MethodHandleLinkTo* nodes have a trailing MemberName argument which
         // needs to be popped.
-        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
         ValueNode[] targetArguments;
         switch (intrinsicMethod) {
             case INVOKE_BASIC:
-                targetArguments = originalArguments;
+                targetArguments = arguments;
                 break;
             case LINK_TO_STATIC:
             case LINK_TO_SPECIAL:
             case LINK_TO_VIRTUAL:
             case LINK_TO_INTERFACE:
-                targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
+                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
 
-        // If there is already replacement information, use that instead.
-        MethodCallTargetNode callTarget;
-        if (replacementTargetMethod == null) {
-            callTarget = new SelfReplacingMethodCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnType, getTargetMethod(), originalArguments, getReturnType());
-        } else {
-            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
-            callTarget = new SelfReplacingMethodCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnType, replacementTargetMethod, args, replacementReturnType);
-        }
-        graph().add(callTarget);
+        MethodCallTargetNode callTarget = new ResolvedMethodHandleCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType);
 
         // The call target can have a different return type than the invoker,
         // e.g. the target returns an Object but the invoker void. In this case
         // we need to use the stamp of the invoker. Note: always using the
         // invoker's stamp would be wrong because it's a less concrete type
         // (usually java.lang.Object).
-        InvokeNode invoke;
-        if (stamp() == StampFactory.forVoid()) {
-            invoke = new InvokeNode(callTarget, getBci(), stamp());
+        if (returnType.getKind() == Kind.Void) {
+            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
         } else {
-            invoke = new InvokeNode(callTarget, getBci());
+            return new InvokeNode(callTarget, bci);
         }
-        graph().add(invoke);
-        invoke.setStateAfter(stateAfter());
-        return invoke;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
@@ -43,8 +44,8 @@
 
     public static final NodeClass<ObjectCloneNode> TYPE = NodeClass.create(ObjectCloneNode.class);
 
-    public ObjectCloneNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ObjectCloneNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Fri Mar 27 13:29:08 2015 +0100
@@ -28,7 +28,6 @@
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
 
 /**
  * Substitutions for {@link java.lang.Object} methods.
@@ -51,7 +50,4 @@
     public static void init(Object thisObj) {
         RegisterFinalizerNode.register(thisObj);
     }
-
-    @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false, forced = true)
-    public static native Object clone(Object obj);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
@@ -39,8 +40,8 @@
 
     public static final NodeClass<ReflectionGetCallerClassNode> TYPE = NodeClass.create(ReflectionGetCallerClassNode.class);
 
-    public ReflectionGetCallerClassNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ReflectionGetCallerClassNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Fri Mar 27 13:29:08 2015 +0100
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
 
 /**
  * Substitutions for {@link sun.reflect.Reflection} methods.
@@ -37,9 +36,6 @@
 @ClassSubstitution(sun.reflect.Reflection.class)
 public class ReflectionSubstitutions {
 
-    @MacroSubstitution(macro = ReflectionGetCallerClassNode.class, optional = true)
-    public static native Class<?> getCallerClass();
-
     @MethodSubstitution
     public static int getClassAccessFlags(Class<?> aClass) {
         KlassPointer klass = ClassGetHubNode.readClass(GuardingPiNode.asNonNullClass(aClass));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -29,6 +29,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -36,8 +37,8 @@
 
     public static final NodeClass<SystemIdentityHashCodeNode> TYPE = NodeClass.create(SystemIdentityHashCodeNode.class);
 
-    public SystemIdentityHashCodeNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public SystemIdentityHashCodeNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode object) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, object);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Fri Mar 27 13:29:08 2015 +0100
@@ -27,8 +27,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.replacements.arraycopy.*;
-import com.oracle.graal.nodes.spi.*;
 
 /**
  * Substitutions for {@link java.lang.System} methods.
@@ -39,10 +37,6 @@
     public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class);
     public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class);
 
-    @MacroSubstitution(macro = ArrayCopyNode.class)
-    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
-
-    @MacroSubstitution(macro = SystemIdentityHashCodeNode.class)
     @MethodSubstitution
     public static int identityHashCode(Object x) {
         if (probability(NOT_FREQUENT_PROBABILITY, x == null)) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
@@ -43,8 +44,8 @@
 
     public static final NodeClass<ArrayCopyNode> TYPE = NodeClass.create(ArrayCopyNode.class);
 
-    public ArrayCopyNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ArrayCopyNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, src, srcPos, dst, dstPos, length);
     }
 
     private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 27 13:29:08 2015 +0100
@@ -1143,6 +1143,21 @@
                 }
             }
 
+            private InvokeKind currentInvokeKind;
+            private JavaType currentInvokeReturnType;
+
+            public InvokeKind getInvokeKind() {
+                return currentInvokeKind;
+            }
+
+            public JavaType getInvokeReturnType() {
+                return currentInvokeReturnType;
+            }
+
+            public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
+                appendInvoke(invokeKind, targetMethod, args);
+            }
+
             private void appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
                 ResolvedJavaMethod targetMethod = initialTargetMethod;
                 InvokeKind invokeKind = initialInvokeKind;
@@ -1179,22 +1194,29 @@
                     }
                 }
 
-                if (tryGenericInvocationPlugin(args, targetMethod)) {
-                    if (TraceParserPlugins.getValue()) {
-                        traceWithContext("used generic invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                try {
+                    currentInvokeReturnType = returnType;
+                    currentInvokeKind = invokeKind;
+                    if (tryGenericInvocationPlugin(args, targetMethod)) {
+                        if (TraceParserPlugins.getValue()) {
+                            traceWithContext("used generic invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                        }
+                        return;
                     }
-                    return;
-                }
 
-                if (tryInvocationPlugin(args, targetMethod, resultType)) {
-                    if (TraceParserPlugins.getValue()) {
-                        traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                    if (tryInvocationPlugin(args, targetMethod, resultType)) {
+                        if (TraceParserPlugins.getValue()) {
+                            traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                        }
+                        return;
                     }
-                    return;
-                }
 
-                if (tryInline(args, targetMethod, invokeKind, returnType)) {
-                    return;
+                    if (tryInline(args, targetMethod, invokeKind, returnType)) {
+                        return;
+                    }
+                } finally {
+                    currentInvokeReturnType = null;
+                    currentInvokeKind = null;
                 }
 
                 MethodCallTargetNode callTarget = currentGraph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnType));
@@ -1252,7 +1274,8 @@
 
                 boolean check(boolean pluginResult) {
                     if (pluginResult == true) {
-                        assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : error("plugin manipulated the stack incorrectly");
+                        int expectedStackSize = beforeStackSize + resultType.getSlotCount();
+                        assert expectedStackSize == frameState.stackSize : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize);
                         NodeIterable<Node> newNodes = currentGraph.getNewNodes(mark);
                         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) {
@@ -1278,6 +1301,15 @@
             private boolean tryInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
                 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
                 if (plugin != null) {
+
+                    ReplacementContext context = this.replacementContext;
+                    if (context != null && context.isCallToOriginal(targetMethod)) {
+                        // Self recursive replacement means the original
+                        // method should be called.
+                        assert !targetMethod.hasBytecodes() : "TODO: when does this happen?";
+                        return false;
+                    }
+
                     InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
                     if (InvocationPlugin.execute(this, targetMethod, plugin, invocationPluginReceiver.init(targetMethod, args), args)) {
                         assert assertions.check(true);
@@ -1305,7 +1337,7 @@
                 return false;
             }
 
-            boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, InlineInfo inlineInfo, ValueNode[] args) {
+            public boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, InlineInfo inlineInfo, ValueNode[] args) {
                 int bci = bci();
                 ResolvedJavaMethod inlinedMethod = inlineInfo.methodToInline;
                 if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A SelfReplacingMethodCallTargetNode replaces itself in the graph when being lowered with a
- * {@link MethodCallTargetNode} that calls the stored replacement target method.
- *
- * This node is used for method handle call nodes which have a constant call target but are not
- * inlined.
- */
-@NodeInfo
-public final class SelfReplacingMethodCallTargetNode extends MethodCallTargetNode implements Lowerable {
-
-    public static final NodeClass<SelfReplacingMethodCallTargetNode> TYPE = NodeClass.create(SelfReplacingMethodCallTargetNode.class);
-    // Replacement method data
-    protected final ResolvedJavaMethod replacementTargetMethod;
-    protected final JavaType replacementReturnType;
-    @Input NodeInputList<ValueNode> replacementArguments;
-
-    public SelfReplacingMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod replacementTargetMethod,
-                    ValueNode[] replacementArguments, JavaType replacementReturnType) {
-        super(TYPE, invokeKind, targetMethod, arguments, returnType);
-        this.replacementTargetMethod = replacementTargetMethod;
-        this.replacementReturnType = replacementReturnType;
-        this.replacementArguments = new NodeInputList<>(this, replacementArguments);
-    }
-
-    public ResolvedJavaMethod replacementTargetMethod() {
-        return replacementTargetMethod;
-    }
-
-    public JavaType replacementReturnType() {
-        return replacementReturnType;
-    }
-
-    public NodeInputList<ValueNode> replacementArguments() {
-        return replacementArguments;
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        InvokeKind replacementInvokeKind = replacementTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        MethodCallTargetNode replacement = graph().add(
-                        new MethodCallTargetNode(replacementInvokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
-
-        // Replace myself...
-        this.replaceAndDelete(replacement);
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri Mar 27 13:29:08 2015 +0100
@@ -212,7 +212,7 @@
         if (callTarget.targetMethod() == null) {
             return "target method is null";
         }
-        assert invoke.stateAfter() != null;
+        assert invoke.stateAfter() != null : invoke;
         if (!invoke.useForInlining()) {
             return "the invoke is marked to be not used for inlining";
         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Fri Mar 27 13:29:08 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements.test;
 
+import java.util.function.*;
+
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
@@ -34,6 +36,9 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.runtime.*;
 
+/**
+ * Tests for expected behavior when parsing snippets and intrinsics.
+ */
 public class ReplacementsParseTest extends GraalCompilerTest {
 
     private static final Object THROW_EXCEPTION_MARKER = new Object() {
@@ -64,6 +69,10 @@
             }
             return res;
         }
+
+        static String identity(String s) {
+            return s;
+        }
     }
 
     @ClassSubstitution(TestMethods.class)
@@ -75,11 +84,17 @@
             return Math.nextAfter(xx, d);
         }
 
+        /**
+         * Tests partial intrinsification.
+         */
         @MethodSubstitution
         static String stringize(Object obj) {
             if (obj != null && obj.getClass() == String.class) {
                 return asNonNullString(obj);
             } else {
+                // A recursive call denotes exiting/deoptimizing
+                // out of the partial intrinsification to the
+                // slow/uncommon case.
                 return stringize(obj);
             }
         }
@@ -91,6 +106,17 @@
         @NodeIntrinsic(PiNode.class)
         private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
 
+        /**
+         * Tests that non-capturing lambdas are folded away.
+         */
+        @MethodSubstitution
+        static String identity(String value) {
+            return apply(s -> s, value);
+        }
+
+        private static String apply(Function<String, String> f, String value) {
+            return f.apply(value);
+        }
     }
 
     private static boolean substitutionsInstalled;
@@ -156,7 +182,7 @@
         test("callStringize", Boolean.TRUE);
     }
 
-    public Object callStringize(Object obj) {
+    public static Object callStringize(Object obj) {
         return TestMethods.stringize(obj);
     }
 
@@ -167,4 +193,14 @@
         test(method, null, Boolean.TRUE);
         test(method, null, THROW_EXCEPTION_MARKER);
     }
+
+    @Test
+    public void testLambda() {
+        test("callLambda", (String) null);
+        test("callLambda", "a string");
+    }
+
+    public static String callLambda(String value) {
+        return TestMethods.identity(value);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri Mar 27 13:29:08 2015 +0100
@@ -85,7 +85,7 @@
                 if (!COULD_NOT_FOLD.equals(constant)) {
                     if (constant != null) {
                         // Replace the invoke with the result of the call
-                        ConstantNode res = b.append(ConstantNode.forConstant(constant, b.getMetaAccess()));
+                        ConstantNode res = b.add(ConstantNode.forConstant(constant, b.getMetaAccess()));
                         b.addPush(res.getKind().getStackKind(), res);
                     } else {
                         // This must be a void invoke
@@ -123,7 +123,7 @@
         }
         if (res instanceof UnsafeCopyNode) {
             UnsafeCopyNode copy = (UnsafeCopyNode) res;
-            UnsafeLoadNode value = b.append(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
+            UnsafeLoadNode value = b.add(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
             b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
             return true;
         } else if (res instanceof ForeignCallNode) {
@@ -131,7 +131,7 @@
             foreign.setBci(b.bci());
         }
 
-        res = b.append(res);
+        res = b.add(res);
 
         InputType inputType = InputType.Value;
         if (returnKind == Kind.Object && stamp instanceof ObjectStamp) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri Mar 27 13:29:08 2015 +0100
@@ -27,7 +27,6 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation;
 
@@ -42,7 +41,6 @@
     /**
      * Special cases from {@link Math#pow} and __ieee754_pow (in sharedRuntimeTrans.cpp).
      */
-    @MacroSubstitution(macro = MathPowNode.class)
     @MethodSubstitution(guard = MathGuard.class)
     public static double pow(double x, double y) {
         // If the second argument is positive or negative zero, then the result is 1.0.
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Fri Mar 27 13:29:08 2015 +0100
@@ -180,9 +180,9 @@
         r.register1("reverseBytes", char.class, new InvocationPlugin() {
             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))));
-                ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
+                ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
+                ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
                 b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
@@ -194,9 +194,9 @@
         r.register1("reverseBytes", short.class, new InvocationPlugin() {
             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))));
-                SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
+                ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
+                SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
                 b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
@@ -255,6 +255,17 @@
                 return true;
             }
         });
+        r.register2("pow", Double.TYPE, Double.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                ValueNode folded = MathPowNode.tryFold(x, y);
+                if (folded != null) {
+                    b.addPush(Kind.Double, folded);
+                } else {
+                    b.addPush(Kind.Double, new MathPowNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), x, y));
+                }
+                return true;
+            }
+        });
         if (getAndSetEnabled(arch)) {
             r.register1("log", Double.TYPE, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
@@ -363,7 +374,7 @@
         Registration r = new Registration(plugins, Class.class);
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
-                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object));
+                LogicNode condition = b.add(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object));
                 b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
@@ -375,18 +386,6 @@
                 return true;
             }
         });
-        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
-                if (receiver.isConstant()) {
-                    ResolvedJavaType type = b.getConstantReflection().asJavaType(receiver.get().asConstant());
-                    if (type != null && !type.isPrimitive()) {
-                        b.addPush(Kind.Object, CheckCastNode.create(type, object, null, false, b.getAssumptions()));
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
     }
 
     /**
@@ -401,7 +400,7 @@
         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, Receiver receiver, ValueNode node, ValueNode offset) {
-                    ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any()));
+                    ValueNode value = b.add(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any()));
                     boolean exactType = false;
                     boolean nonNull = false;
                     b.addPush(Kind.Object, new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull));
@@ -493,11 +492,11 @@
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
             if (isVolatile) {
-                b.append(new MembarNode(JMM_PRE_VOLATILE_READ));
+                b.add(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
             b.addPush(returnKind.getStackKind(), new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any()));
             if (isVolatile) {
-                b.append(new MembarNode(JMM_POST_VOLATILE_READ));
+                b.add(new MembarNode(JMM_POST_VOLATILE_READ));
             }
             return true;
         }
@@ -516,7 +515,7 @@
         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));
+            b.add(new DirectStoreNode(address, value, kind));
             return true;
         }
 
@@ -524,11 +523,11 @@
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
             if (isVolatile) {
-                b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
             b.add(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any()));
             if (isVolatile) {
-                b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
             return true;
         }
@@ -538,14 +537,14 @@
         Registration r = new Registration(plugins, GraalDirectives.class);
         r.register0("deoptimize", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
 
         r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
@@ -559,7 +558,7 @@
 
         r.register0("controlFlowAnchor", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new ControlFlowAnchorNode());
+                b.add(new ControlFlowAnchorNode());
                 return true;
             }
         });
@@ -573,7 +572,7 @@
 
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.append(new BlackholeNode(value));
+                b.add(new BlackholeNode(value));
                 return true;
             }
         };
@@ -598,7 +597,7 @@
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) {
                 blackhole.get();
-                b.append(new BlackholeNode(value));
+                b.add(new BlackholeNode(value));
                 return true;
             }
         };
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Fri Mar 27 13:29:08 2015 +0100
@@ -91,7 +91,7 @@
 
             case NOT:
                 assert args.length == 1;
-                b.addPush(returnStackKind, new XorNode(args[0], b.append(forIntegerKind(wordKind, -1))));
+                b.addPush(returnStackKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
                 break;
 
             case READ_POINTER:
@@ -158,7 +158,7 @@
 
             case FROM_OBJECT:
                 assert args.length == 1;
-                WordCastNode objectToWord = b.append(WordCastNode.objectToWord(args[0], wordKind));
+                WordCastNode objectToWord = b.add(WordCastNode.objectToWord(args[0], wordKind));
                 b.push(returnStackKind, objectToWord);
                 break;
 
@@ -169,7 +169,7 @@
 
             case TO_OBJECT:
                 assert args.length == 1;
-                WordCastNode wordToObject = b.append(WordCastNode.wordToObject(args[0], wordKind));
+                WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
                 b.push(returnStackKind, wordToObject);
                 break;
 
@@ -210,15 +210,15 @@
             comparison = new IntegerLessThanNode(a, b);
         }
 
-        ConstantNode trueValue = graph.append(forInt(1));
-        ConstantNode falseValue = graph.append(forInt(0));
+        ConstantNode trueValue = graph.add(forInt(1));
+        ConstantNode falseValue = graph.add(forInt(0));
 
         if (condition.canonicalNegate()) {
             ConstantNode temp = trueValue;
             trueValue = falseValue;
             falseValue = temp;
         }
-        ConditionalNode materialize = graph.append(new ConditionalNode(graph.append(comparison), trueValue, falseValue));
+        ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
         return materialize;
     }
 
@@ -231,7 +231,7 @@
     }
 
     public static ValueNode readOp(GraphBuilderContext b, Kind readKind, ValueNode base, LocationNode location, BarrierType barrierType, boolean compressible) {
-        JavaReadNode read = b.append(new JavaReadNode(readKind, base, location, barrierType, compressible));
+        JavaReadNode read = b.add(new JavaReadNode(readKind, base, location, barrierType, compressible));
         /*
          * The read must not float outside its block otherwise it may float above an explicit zero
          * check on its base address.
@@ -249,14 +249,14 @@
     }
 
     public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, LocationIdentity locationIdentity) {
-        return b.append(new IndexedLocationNode(locationIdentity, 0, fromSigned(b, offset), 1));
+        return b.add(new IndexedLocationNode(locationIdentity, 0, fromSigned(b, offset), 1));
     }
 
     public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, ValueNode locationIdentity) {
         if (locationIdentity.isConstant()) {
             return makeLocation(b, offset, snippetReflection.asObject(LocationIdentity.class, locationIdentity.asJavaConstant()));
         }
-        return b.append(new SnippetLocationNode(snippetReflection, locationIdentity, b.append(ConstantNode.forLong(0)), fromSigned(b, offset), b.append(ConstantNode.forInt(1))));
+        return b.add(new SnippetLocationNode(snippetReflection, locationIdentity, b.add(ConstantNode.forLong(0)), fromSigned(b, offset), b.add(ConstantNode.forInt(1))));
     }
 
     public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
@@ -278,14 +278,14 @@
 
         if (toKind == Kind.Int) {
             assert value.getKind() == Kind.Long;
-            return b.append(new NarrowNode(value, 32));
+            return b.add(new NarrowNode(value, 32));
         } else {
             assert toKind == Kind.Long;
             assert value.getKind().getStackKind() == Kind.Int;
             if (unsigned) {
-                return b.append(new ZeroExtendNode(value, 64));
+                return b.add(new ZeroExtendNode(value, 64));
             } else {
-                return b.append(new SignExtendNode(value, 64));
+                return b.add(new SignExtendNode(value, 64));
             }
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -36,8 +37,8 @@
 
     public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
 
-    public BasicArrayCopyNode(NodeClass<? extends BasicArrayCopyNode> c, Invoke invoke) {
-        super(c, invoke);
+    public BasicArrayCopyNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     protected ValueNode getSource() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -40,8 +41,8 @@
 
     public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class);
 
-    protected BasicObjectCloneNode(NodeClass<? extends BasicObjectCloneNode> c, Invoke invoke) {
-        super(c, invoke);
+    public BasicObjectCloneNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -42,9 +42,8 @@
 import com.oracle.graal.replacements.*;
 
 /**
- * Macro nodes can be used to temporarily replace an invoke (usually by using the
- * {@link MacroSubstitution} annotation). They can, for example, be used to implement constant
- * folding for known JDK functions like {@link Class#isInterface()}.<br/>
+ * Macro nodes can be used to temporarily replace an invoke. They can, for example, be used to
+ * implement constant folding for known JDK functions like {@link Class#isInterface()}.<br/>
  * <br/>
  * During lowering, multiple sources are queried in order to look for a replacement:
  * <ul>
@@ -77,6 +76,16 @@
         this.invokeKind = methodCallTarget.invokeKind();
     }
 
+    protected MacroNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, StampFactory.forKind(returnType.getKind()));
+        assert targetMethod.getSignature().getParameterCount(!targetMethod.isStatic()) == arguments.length;
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.bci = bci;
+        this.targetMethod = targetMethod;
+        this.returnType = returnType;
+        this.invokeKind = invokeKind;
+    }
+
     public int getBci() {
         return bci;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 
@@ -41,9 +42,8 @@
     public static final NodeClass<MacroStateSplitNode> TYPE = NodeClass.create(MacroStateSplitNode.class);
     @OptionalInput(InputType.State) protected FrameState stateAfter;
 
-    public MacroStateSplitNode(NodeClass<? extends MacroStateSplitNode> c, Invoke invoke) {
-        super(c, invoke);
-        this.stateAfter = invoke.stateAfter();
+    protected MacroStateSplitNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -22,28 +22,34 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 @NodeInfo
 public final class MathPowNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
     public static final NodeClass<MathPowNode> TYPE = NodeClass.create(MathPowNode.class);
 
-    public MathPowNode(Invoke i) {
-        super(TYPE, i);
+    public MathPowNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode x, ValueNode y) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, x, y);
     }
 
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && forY.isConstant()) {
-            double x = forX.asJavaConstant().asDouble();
-            double y = forY.asJavaConstant().asDouble();
-            return ConstantNode.forDouble(Math.pow(x, y));
-        } else {
-            return this;
+        ValueNode folded = tryFold(forX, forY);
+        return folded != null ? folded : this;
+    }
+
+    public static ValueNode tryFold(ValueNode x, ValueNode y) {
+        if (x.isConstant() && y.isConstant()) {
+            double xPrim = x.asJavaConstant().asDouble();
+            double yPrim = y.asJavaConstant().asDouble();
+            return ConstantNode.forDouble(Math.pow(xPrim, yPrim));
         }
+        return null;
     }
 
     public ValueNode getX() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 /**
  * This node class can be used to create {@link MacroNode}s for simple pure functions like
@@ -37,8 +38,8 @@
 
     public static final NodeClass<PureFunctionMacroNode> TYPE = NodeClass.create(PureFunctionMacroNode.class);
 
-    protected PureFunctionMacroNode(NodeClass<? extends PureFunctionMacroNode> c, Invoke invoke) {
-        super(c, invoke);
+    public PureFunctionMacroNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     /**
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Mar 27 13:29:08 2015 +0100
@@ -162,7 +162,7 @@
 
         public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
             if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) {
-                ConstantNode trueNode = builder.append(ConstantNode.forBoolean(true));
+                ConstantNode trueNode = builder.add(ConstantNode.forBoolean(true));
                 builder.addPush(trueNode);
                 return true;
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Mar 27 13:29:08 2015 +0100
@@ -31,8 +31,6 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.truffle.substitutions.*;
-import com.oracle.truffle.api.*;
 
 /**
  * Custom {@link Replacements} for Truffle compilation.
@@ -44,15 +42,6 @@
     protected TruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) {
         super(providers, snippetReflection, providers.getCodeCache().getTarget());
         this.graalReplacements = providers.getReplacements();
-
-        registerTruffleSubstitutions();
-    }
-
-    protected void registerTruffleSubstitutions() {
-        if (!TruffleCompilerOptions.FastPE.getValue()) {
-            registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
-            registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
-        }
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.truffle.*;
-
-@NodeInfo
-public final class AssumptionNode extends MacroNode implements Simplifiable {
-
-    public static final NodeClass<AssumptionNode> TYPE = NodeClass.create(AssumptionNode.class);
-
-    public AssumptionNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert super.arguments.size() == 1;
-    }
-
-    private ValueNode getAssumption() {
-        return arguments.first();
-    }
-
-    private static SnippetReflectionProvider getSnippetReflection() {
-        /*
-         * This class requires access to the objects encapsulated in Constants, and therefore breaks
-         * the compiler-VM separation of object constants.
-         */
-        return Graal.getRequiredCapability(SnippetReflectionProvider.class);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        throw new GraalInternalError(GraphUtil.approxSourceException(this, new RuntimeException("assumption could not be evaluated to a constant")));
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        ValueNode assumption = getAssumption();
-        Assumptions assumptions = graph().getAssumptions();
-        if (assumption.isConstant()) {
-            JavaConstant c = assumption.asJavaConstant();
-            assert c.getKind() == Kind.Object;
-            Object object = getSnippetReflection().asObject(Object.class, c);
-            OptimizedAssumption assumptionObject = (OptimizedAssumption) object;
-            StructuredGraph graph = graph();
-            if (assumptionObject.isValid()) {
-                assumptions.record(new AssumptionValidAssumption(assumptionObject));
-                if (super.getReturnType().getKind() == Kind.Boolean) {
-                    graph.replaceFixedWithFloating(this, ConstantNode.forBoolean(true, graph()));
-                } else {
-                    graph.removeFixed(this);
-                }
-            } else {
-                if (super.getReturnType().getKind() == Kind.Boolean) {
-                    graph.replaceFixedWithFloating(this, ConstantNode.forBoolean(false, graph()));
-                } else {
-                    tool.deleteBranch(this.next());
-                    this.replaceAndDelete(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.None)));
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.asserts;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.nodes.*;
-
-@NodeInfo
-public final class NeverInlineMacroNode extends MacroStateSplitNode implements com.oracle.graal.graph.IterableNodeType {
-
-    public static final NodeClass<NeverInlineMacroNode> TYPE = NodeClass.create(NeverInlineMacroNode.class);
-
-    public NeverInlineMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        InvokeNode invoke = createInvoke();
-        graph().replaceFixedWithFixed(this, invoke);
-        invoke.setUseForInlining(false);
-        invoke.lower(tool);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Mar 27 13:29:08 2015 +0100
@@ -49,7 +49,4 @@
             throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
         }
     }
-
-    @NodeIntrinsic
-    public static native void apply(@ConstantNodeParameter String message);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.truffle.nodes.*;
-
-/**
- * Macro node for CompilerDirectives#unsafeGetInt*.
- */
-@NodeInfo
-public final class CustomizedUnsafeLoadMacroNode extends MacroStateSplitNode implements Canonicalizable {
-    public static final NodeClass<CustomizedUnsafeLoadMacroNode> TYPE = NodeClass.create(CustomizedUnsafeLoadMacroNode.class);
-
-    private static final int ARGUMENT_COUNT = 4;
-    private static final int OBJECT_ARGUMENT_INDEX = 0;
-    private static final int OFFSET_ARGUMENT_INDEX = 1;
-    private static final int CONDITION_ARGUMENT_INDEX = 2;
-    private static final int LOCATION_ARGUMENT_INDEX = 3;
-
-    public CustomizedUnsafeLoadMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert arguments.size() == ARGUMENT_COUNT;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode locationArgument = arguments.get(LOCATION_ARGUMENT_INDEX);
-        if (locationArgument.isConstant()) {
-            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
-            ValueNode offsetArgument = arguments.get(OFFSET_ARGUMENT_INDEX);
-            ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
-            LocationIdentity locationIdentity;
-            if (locationArgument.isNullConstant()) {
-                locationIdentity = LocationIdentity.any();
-            } else {
-                locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
-            }
-            LogicNode compare = CompareNode.createCompareNode(Condition.EQ, conditionArgument, ConstantNode.forBoolean(true), tool.getConstantReflection());
-            Kind returnKind = this.getTargetMethod().getSignature().getReturnKind();
-            return new UnsafeLoadNode(objectArgument, offsetArgument, returnKind, locationIdentity, compare);
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.truffle.nodes.*;
-
-/**
- * Macro node for method CompilerDirectives#unsafePut*.
- */
-@NodeInfo
-public final class CustomizedUnsafeStoreMacroNode extends MacroStateSplitNode implements Canonicalizable, StateSplit {
-    public static final NodeClass<CustomizedUnsafeStoreMacroNode> TYPE = NodeClass.create(CustomizedUnsafeStoreMacroNode.class);
-    private static final int ARGUMENT_COUNT = 4;
-    private static final int OBJECT_ARGUMENT_INDEX = 0;
-    private static final int OFFSET_ARGUMENT_INDEX = 1;
-    private static final int VALUE_ARGUMENT_INDEX = 2;
-    private static final int LOCATION_ARGUMENT_INDEX = 3;
-
-    public CustomizedUnsafeStoreMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert arguments.size() == ARGUMENT_COUNT;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode locationArgument = arguments.get(LOCATION_ARGUMENT_INDEX);
-        if (locationArgument.isConstant()) {
-            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
-            ValueNode offsetArgument = arguments.get(OFFSET_ARGUMENT_INDEX);
-            ValueNode valueArgument = arguments.get(VALUE_ARGUMENT_INDEX);
-            LocationIdentity locationIdentity;
-            if (locationArgument.isNullConstant()) {
-                locationIdentity = LocationIdentity.any();
-            } else {
-                locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
-            }
-
-            return new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, this.getTargetMethod().getSignature().getParameterKind(VALUE_ARGUMENT_INDEX), locationIdentity, stateAfter());
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Macro node for method CompilerDirectives#unsafeCast.
- */
-@NodeInfo
-public final class UnsafeTypeCastMacroNode extends MacroStateSplitNode implements Simplifiable {
-
-    public static final NodeClass<UnsafeTypeCastMacroNode> TYPE = NodeClass.create(UnsafeTypeCastMacroNode.class);
-    private static final int OBJECT_ARGUMENT_INDEX = 0;
-    private static final int CLASS_ARGUMENT_INDEX = 1;
-    private static final int CONDITION_ARGUMENT_INDEX = 2;
-    private static final int NONNULL_ARGUMENT_INDEX = 3;
-    private static final int ARGUMENT_COUNT = 4;
-
-    public UnsafeTypeCastMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert arguments.size() == ARGUMENT_COUNT;
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        ValueNode classArgument = arguments.get(CLASS_ARGUMENT_INDEX);
-        ValueNode nonNullArgument = arguments.get(NONNULL_ARGUMENT_INDEX);
-        if (classArgument.isConstant() && nonNullArgument.isConstant()) {
-            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
-            ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
-            ResolvedJavaType lookupJavaType = tool.getConstantReflection().asJavaType(classArgument.asConstant());
-            tool.addToWorkList(usages());
-            if (lookupJavaType == null) {
-                replaceAtUsages(objectArgument);
-                GraphUtil.removeFixedWithUnusedInputs(this);
-            } else {
-                Stamp piStamp = StampFactory.declaredTrusted(lookupJavaType, nonNullArgument.asJavaConstant().asInt() != 0);
-                ConditionAnchorNode valueAnchorNode = graph().add(
-                                new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()), tool.getConstantReflection())));
-                PiNode piCast = graph().unique(new PiNode(objectArgument, piStamp, valueAnchorNode));
-                replaceAtUsages(piCast);
-                graph().replaceFixedWithFixed(this, valueAnchorNode);
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.truffle.nodes.asserts.*;
-import com.oracle.truffle.api.*;
-
-@ClassSubstitution(CompilerAsserts.class)
-public class CompilerAssertsSubstitutions {
-
-    @MethodSubstitution
-    public static void neverPartOfCompilation(@SuppressWarnings("unused") String message) {
-        NeverPartOfCompilationNode.apply("Never part of compilation");
-    }
-
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedAssumptionSubstitutions.java	Fri Mar 27 00:41:11 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.*;
-
-@ClassSubstitution(OptimizedAssumption.class)
-public class OptimizedAssumptionSubstitutions {
-
-    @MacroSubstitution(macro = AssumptionNode.class, isStatic = false, forced = true)
-    public static native void check(OptimizedAssumption assumption);
-
-    @MacroSubstitution(macro = AssumptionNode.class, isStatic = false, forced = true)
-    public static native boolean isValid(OptimizedAssumption assumption);
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri Mar 27 00:41:11 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri Mar 27 13:29:08 2015 +0100
@@ -55,6 +55,7 @@
         registerOptimizedAssumptionPlugins(plugins);
         registerExactMathPlugins(plugins);
         registerCompilerDirectivesPlugins(plugins);
+        registerCompilerAssertsPlugins(plugins);
         registerOptimizedCallTargetPlugins(metaAccess, plugins);
         registerUnsafeAccessImplPlugins(plugins);
 
@@ -68,21 +69,34 @@
 
     public static void registerOptimizedAssumptionPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, OptimizedAssumption.class);
-        r.register1("isValid", Receiver.class, new InvocationPlugin() {
+        InvocationPlugin plugin = new InvocationPlugin() {
             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.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(assumption.isValid()));
                     if (assumption.isValid()) {
+                        if (targetMethod.getName().equals("isValid")) {
+                            b.addPush(ConstantNode.forBoolean(true));
+                        } else {
+                            assert targetMethod.getName().equals("check") : targetMethod;
+                        }
                         b.getAssumptions().record(new AssumptionValidAssumption(assumption));
+                    } else {
+                        if (targetMethod.getName().equals("isValid")) {
+                            b.addPush(ConstantNode.forBoolean(false));
+                        } else {
+                            assert targetMethod.getName().equals("check") : targetMethod;
+                            b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.None));
+                        }
                     }
                 } else {
                     throw b.bailout("assumption could not be reduced to a constant");
                 }
                 return true;
             }
-        });
+        };
+        r.register1("isValid", Receiver.class, plugin);
+        r.register1("check", Receiver.class, plugin);
     }
 
     public static void registerExactMathPlugins(InvocationPlugins plugins) {
@@ -138,13 +152,13 @@
         });
         r.register0("transferToInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
         r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
@@ -184,12 +198,14 @@
         });
         r.register1("materialize", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.append(new ForceMaterializeNode(value));
+                b.add(new ForceMaterializeNode(value));
                 return true;
             }
         });
+    }
 
-        r = new Registration(plugins, CompilerAsserts.class);
+    public static void registerCompilerAssertsPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, CompilerAsserts.class);
         r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 ValueNode curValue = value;
@@ -219,7 +235,7 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
                 if (message.isConstant()) {
                     String messageString = message.asConstant().toValueString();
-                    b.append(new NeverPartOfCompilationNode(messageString));
+                    b.add(new NeverPartOfCompilationNode(messageString));
                     return true;
                 }
                 throw b.bailout("message for never part of compilation is non-constant");
@@ -301,7 +317,7 @@
                         }
                         ConditionAnchorNode valueAnchorNode = null;
                         if (!skipAnchor) {
-                            valueAnchorNode = b.append(new ConditionAnchorNode(compareNode));
+                            valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
                         }
                         b.addPush(Kind.Object, new PiNode(object, piStamp, valueAnchorNode));
                     }
@@ -339,8 +355,8 @@
                 } else {
                     locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
                 }
-                LogicNode compare = b.append(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), b.getConstantReflection()));
-                b.addPush(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
+                LogicNode compare = b.add(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), b.getConstantReflection()));
+                b.addPush(returnKind.getStackKind(), b.add(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
                 return true;
             }
             // TODO: should we throw GraalInternalError.shouldNotReachHere() here?