changeset 23078:b00ef2b9cd00

Generate graph builder plugins for @NodeIntrinsic and @Fold methods.
author Roland Schatz <roland.schatz@oracle.com>
date Tue, 24 Nov 2015 19:31:56 +0100
parents 84586c6568dd
children a6b3ae072073
files graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/SnippetReflectionProvider.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.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/HotSpotSnippetReflectionProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/RuntimeStringSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCopyNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GeneratedInvocationPlugin.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugins.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathSubstitutions.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/FoldPluginGenerator.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/InjectedDependencies.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicPluginGenerator.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsicFactory.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java mx.graal/suite.py
diffstat 45 files changed, 1501 insertions(+), 536 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/SnippetReflectionProvider.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/SnippetReflectionProvider.java	Tue Nov 24 19:31:56 2015 +0100
@@ -182,5 +182,5 @@
      * @return the value that should be bound to the parameter when invoking the constructor or null
      *         if this provider cannot provide a value of the requested type
      */
-    Object getInjectedNodeIntrinsicParameter(ResolvedJavaType type);
+    <T> T getInjectedNodeIntrinsicParameter(Class<T> type);
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -163,7 +163,11 @@
      * annotated method can be replaced with an instance of the node class denoted by
      * {@link #value()}. For this reason, the signature of the annotated method must match the
      * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a
-     * factory method named {@code "create"} in the node class.
+     * constructor in the node class.
+     * <p>
+     * If the node class has a static method {@code intrinsify} with a matching signature plus a
+     * {@code GraphBuilderContext} as first argument, this method is called instead of creating the
+     * node.
      */
     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
     @java.lang.annotation.Target(ElementType.METHOD)
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Nov 24 19:31:56 2015 +0100
@@ -66,6 +66,7 @@
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.replacements.amd64.AMD64GraphBuilderPlugins;
+import com.oracle.graal.word.WordTypes;
 
 @ServiceProvider(HotSpotBackendFactory.class)
 public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory {
@@ -112,15 +113,15 @@
             HotSpotStampProvider stampProvider = new HotSpotStampProvider();
             Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
 
+            try (InitTimer rt = timer("create WordTypes")) {
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+            }
             try (InitTimer rt = timer("create SnippetReflection provider")) {
-                snippetReflection = createSnippetReflection(graalRuntime, constantReflection);
+                snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
             }
             try (InitTimer rt = timer("create Replacements provider")) {
                 replacements = createReplacements(config, p, snippetReflection);
             }
-            try (InitTimer rt = timer("create WordTypes")) {
-                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
-            }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
                 plugins = createGraphBuilderPlugins(config, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
                 replacements.setGraphBuilderPlugins(plugins);
@@ -166,8 +167,8 @@
                         registers.getHeapBaseRegister()));
     }
 
-    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection) {
-        return new HotSpotSnippetReflectionProvider(runtime, constantReflection);
+    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
+        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
     }
 
     protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Nov 24 19:31:56 2015 +0100
@@ -88,9 +88,9 @@
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
         HotSpotStampProvider stampProvider = new HotSpotStampProvider();
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
-        HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection);
+        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+        HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, config, target);
-        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
         Plugins plugins = createGraphBuilderPlugins(config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, codeCache);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Nov 24 19:31:56 2015 +0100
@@ -39,6 +39,7 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.options.StableOptionValue;
+import jdk.vm.ci.service.Services;
 import sun.reflect.Reflection;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
@@ -61,13 +62,14 @@
 import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.graphbuilderconf.ForeignCallPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
 import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.graphbuilderconf.MethodSubstitutionPlugin;
-import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
-import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
 import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.memory.address.AddressNode;
 import com.oracle.graal.nodes.memory.address.OffsetAddressNode;
@@ -100,8 +102,8 @@
         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
 
         Plugins plugins = new Plugins(invocationPlugins);
-        NodeIntrinsificationPhase nodeIntrinsificationPhase = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
-        NodeIntrinsificationPlugin nodeIntrinsificationPlugin = new NodeIntrinsificationPlugin(metaAccess, nodeIntrinsificationPhase, wordTypes, false);
+        NodeIntrinsificationPhase nodeIntrinsificationPhase = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, wordTypes);
+        NodeIntrinsificationPlugin nodeIntrinsificationPlugin = new NodeIntrinsificationPlugin();
         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, nodeIntrinsificationPlugin);
 
@@ -125,6 +127,10 @@
         registerCRC32Plugins(invocationPlugins, config);
         StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, true);
 
+        for (NodeIntrinsicPluginFactory factory : Services.load(NodeIntrinsicPluginFactory.class)) {
+            factory.registerPlugin(invocationPlugins, nodeIntrinsificationPhase);
+        }
+
         return plugins;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Tue Nov 24 19:31:56 2015 +0100
@@ -28,20 +28,22 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.word.WordTypes;
 
 public class HotSpotSnippetReflectionProvider implements SnippetReflectionProvider {
 
     private final HotSpotGraalRuntimeProvider runtime;
     private final HotSpotConstantReflectionProvider constantReflection;
+    private final WordTypes wordTypes;
 
-    public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection) {
+    public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
         this.runtime = runtime;
         this.constantReflection = constantReflection;
+        this.wordTypes = wordTypes;
     }
 
     @Override
@@ -88,29 +90,28 @@
     }
 
     // Lazily initialized
-    private ResolvedJavaType wordTypesType;
-    private ResolvedJavaType runtimeType;
-    private ResolvedJavaType configType;
+    private Class<?> wordTypesType;
+    private Class<?> runtimeType;
+    private Class<?> configType;
 
-    public Object getInjectedNodeIntrinsicParameter(ResolvedJavaType type) {
+    public <T> T getInjectedNodeIntrinsicParameter(Class<T> type) {
         // Need to test all fields since there no guarantee under the JMM
         // about the order in which these fields are written.
         HotSpotVMConfig config = config();
         if (configType == null || wordTypesType == null || configType == null) {
-            MetaAccessProvider metaAccess = runtime.getHostProviders().getMetaAccess();
-            wordTypesType = metaAccess.lookupJavaType(runtime.getHostProviders().getWordTypes().getClass());
-            runtimeType = metaAccess.lookupJavaType(runtime.getClass());
-            configType = metaAccess.lookupJavaType(config.getClass());
+            wordTypesType = wordTypes.getClass();
+            runtimeType = runtime.getClass();
+            configType = config.getClass();
         }
 
         if (type.isAssignableFrom(wordTypesType)) {
-            return runtime.getHostProviders().getWordTypes();
+            return type.cast(wordTypes);
         }
         if (type.isAssignableFrom(runtimeType)) {
-            return runtime;
+            return type.cast(runtime);
         }
         if (type.isAssignableFrom(configType)) {
-            return config;
+            return type.cast(config);
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Tue Nov 24 19:31:56 2015 +0100
@@ -48,7 +48,7 @@
      * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}.
      */
     @Fold
-    private static long crcTableAddress() {
+    static long crcTableAddress() {
         return config().crcTableAddress;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Nov 24 19:31:56 2015 +0100
@@ -71,7 +71,7 @@
     }
 
     @Fold
-    private static Class<?> getAESCryptClass() {
+    static Class<?> getAESCryptClass() {
         return AESCryptSubstitutions.AESCryptClass;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Nov 24 19:31:56 2015 +0100
@@ -195,14 +195,14 @@
     public static final LocationIdentity TLAB_END_LOCATION = NamedLocationIdentity.mutable("TlabEnd");
 
     @Fold
-    private static int threadTlabEndOffset() {
+    static int threadTlabEndOffset() {
         return config().threadTlabEndOffset();
     }
 
     public static final LocationIdentity TLAB_START_LOCATION = NamedLocationIdentity.mutable("TlabStart");
 
     @Fold
-    private static int threadTlabStartOffset() {
+    static int threadTlabStartOffset() {
         return config().threadTlabStartOffset();
     }
 
@@ -212,7 +212,7 @@
      * @see HotSpotVMConfig#pendingExceptionOffset
      */
     @Fold
-    private static int threadPendingExceptionOffset() {
+    static int threadPendingExceptionOffset() {
         return config().pendingExceptionOffset;
     }
 
@@ -222,14 +222,14 @@
      * @see HotSpotVMConfig#pendingDeoptimizationOffset
      */
     @Fold
-    private static int threadPendingDeoptimizationOffset() {
+    static int threadPendingDeoptimizationOffset() {
         return config().pendingDeoptimizationOffset;
     }
 
     public static final LocationIdentity OBJECT_RESULT_LOCATION = NamedLocationIdentity.mutable("ObjectResult");
 
     @Fold
-    private static int objectResultOffset() {
+    static int objectResultOffset() {
         return config().threadObjectResultOffset;
     }
 
@@ -503,7 +503,7 @@
     };
 
     @Fold
-    private static int hubOffset() {
+    static int hubOffset() {
         return config().hubOffset;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Nov 24 19:31:56 2015 +0100
@@ -202,7 +202,7 @@
     private static final boolean PROFILE_CONTEXT = false;
 
     @Fold
-    private static boolean doProfile() {
+    static boolean doProfile() {
         return Options.ProfileMonitors.getValue();
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Nov 24 19:31:56 2015 +0100
@@ -138,7 +138,7 @@
     public static final ProfileMode PROFILE_MODE = ProfileMode.AllocatedTypes;
 
     @Fold
-    private static String createName(String path, String typeContext) {
+    static String createName(String path, String typeContext) {
         switch (PROFILE_MODE) {
             case AllocatingMethods:
                 return "";
@@ -155,7 +155,7 @@
     }
 
     @Fold
-    private static boolean doProfile() {
+    static boolean doProfile() {
         return ProfileAllocations.getValue();
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/RuntimeStringSnippets.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/RuntimeStringSnippets.java	Tue Nov 24 19:31:56 2015 +0100
@@ -49,7 +49,7 @@
 public class RuntimeStringSnippets implements Snippets {
 
     @Fold
-    private static long valueOffset() {
+    static long valueOffset() {
         try {
             return UNSAFE.objectFieldOffset(String.class.getDeclaredField("value"));
         } catch (Exception e) {
@@ -58,7 +58,7 @@
     }
 
     @Fold
-    private static long hashOffset() {
+    static long hashOffset() {
         try {
             return UNSAFE.objectFieldOffset(String.class.getDeclaredField("hash"));
         } catch (Exception e) {
@@ -67,7 +67,7 @@
     }
 
     @Fold
-    private static long arrayBaseOffset() {
+    static long arrayBaseOffset() {
         return UNSAFE.arrayBaseOffset(char[].class);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Nov 24 19:31:56 2015 +0100
@@ -285,7 +285,7 @@
     }
 
     @Fold
-    private static LocationIdentity getArrayLocation(JavaKind kind) {
+    static LocationIdentity getArrayLocation(JavaKind kind) {
         return NamedLocationIdentity.getArrayLocation(kind);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Tue Nov 24 19:31:56 2015 +0100
@@ -144,7 +144,7 @@
     }
 
     @Fold
-    private static LocationIdentity getArrayLocation(JavaKind kind) {
+    static LocationIdentity getArrayLocation(JavaKind kind) {
         return NamedLocationIdentity.getArrayLocation(kind);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -154,7 +154,7 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
-         *
+         * 
          * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
@@ -228,7 +228,7 @@
     }
 
     @Fold
-    private static int stackShadowPages() {
+    static int stackShadowPages() {
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
@@ -241,57 +241,57 @@
      */
     @Deprecated
     @Fold
-    private static int stackBias() {
+    static int stackBias() {
         return config().stackBias;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+    static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+    static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
         return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+    static int deoptimizationUnrollBlockNumberOfFramesOffset() {
         return config().deoptimizationUnrollBlockNumberOfFramesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+    static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
         return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockUnpackKindOffset() {
+    static int deoptimizationUnrollBlockUnpackKindOffset() {
         return config().deoptimizationUnrollBlockUnpackKindOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+    static int deoptimizationUnrollBlockFrameSizesOffset() {
         return config().deoptimizationUnrollBlockFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFramePcsOffset() {
+    static int deoptimizationUnrollBlockFramePcsOffset() {
         return config().deoptimizationUnrollBlockFramePcsOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+    static int deoptimizationUnrollBlockInitialInfoOffset() {
         return config().deoptimizationUnrollBlockInitialInfoOffset;
     }
 
     @Fold
-    private static int deoptimizationUnpackDeopt() {
+    static int deoptimizationUnpackDeopt() {
         return config().deoptimizationUnpackDeopt;
     }
 
     @Fold
-    private static int deoptimizationUnpackUncommonTrap() {
+    static int deoptimizationUnpackUncommonTrap() {
         return config().deoptimizationUnpackUncommonTrap;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue Nov 24 19:31:56 2015 +0100
@@ -133,7 +133,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logExceptionHandlerStub");
     }
 
@@ -146,7 +146,7 @@
      */
     @Fold
     @SuppressWarnings("all")
-    private static boolean assertionsEnabled() {
+    static boolean assertionsEnabled() {
         boolean enabled = false;
         assert enabled = true;
         return enabled || cAssertionsEnabled();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -84,7 +84,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logNewArrayStub");
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Nov 24 19:31:56 2015 +0100
@@ -126,7 +126,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logNewInstanceStub");
     }
 
@@ -294,7 +294,7 @@
     }
 
     @Fold
-    private static boolean forceSlowPath() {
+    static boolean forceSlowPath() {
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -252,22 +252,22 @@
     }
 
     @Fold
-    private static long verifyOopCounterAddress() {
+    static long verifyOopCounterAddress() {
         return config().verifyOopCounterAddress;
     }
 
     @Fold
-    private static long verifyOopMask() {
+    static long verifyOopMask() {
         return config().verifyOopMask;
     }
 
     @Fold
-    private static long verifyOopBits() {
+    static long verifyOopBits() {
         return config().verifyOopBits;
     }
 
     @Fold
-    private static int hubOffset() {
+    static int hubOffset() {
         return config().hubOffset;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -156,7 +156,7 @@
     }
 
     @Fold
-    private static int stackShadowPages() {
+    static int stackShadowPages() {
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
@@ -169,52 +169,52 @@
      */
     @Deprecated
     @Fold
-    private static int stackBias() {
+    static int stackBias() {
         return config().stackBias;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+    static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+    static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
         return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+    static int deoptimizationUnrollBlockNumberOfFramesOffset() {
         return config().deoptimizationUnrollBlockNumberOfFramesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+    static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
         return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+    static int deoptimizationUnrollBlockFrameSizesOffset() {
         return config().deoptimizationUnrollBlockFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFramePcsOffset() {
+    static int deoptimizationUnrollBlockFramePcsOffset() {
         return config().deoptimizationUnrollBlockFramePcsOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+    static int deoptimizationUnrollBlockInitialInfoOffset() {
         return config().deoptimizationUnrollBlockInitialInfoOffset;
     }
 
     @Fold
-    private static int deoptimizationUnpackDeopt() {
+    static int deoptimizationUnpackDeopt() {
         return config().deoptimizationUnpackDeopt;
     }
 
     @Fold
-    private static int deoptimizationUnpackUncommonTrap() {
+    static int deoptimizationUnpackUncommonTrap() {
         return config().deoptimizationUnpackUncommonTrap;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -96,7 +96,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logUnwindExceptionToCallerStub");
     }
 
@@ -109,7 +109,7 @@
      */
     @Fold
     @SuppressWarnings("all")
-    private static boolean assertionsEnabled() {
+    static boolean assertionsEnabled() {
         boolean enabled = false;
         assert enabled = true;
         return enabled || cAssertionsEnabled();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Tue Nov 24 19:31:56 2015 +0100
@@ -22,11 +22,16 @@
  */
 package com.oracle.graal.nodes;
 
+import java.util.List;
+
 import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.iterators.NodePredicate;
@@ -161,4 +166,9 @@
             return super.isAllowedUsageType(type);
         }
     }
+
+    public interface NodeIntrinsicConstructor {
+
+        ValueNode newInstance(ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, Graph graph, Object[] injectedArguments, List<? extends ValueNode> arguments);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Nov 24 19:31:56 2015 +0100
@@ -42,6 +42,7 @@
 import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.nodes.memory.AbstractMemoryCheckpoint;
 import com.oracle.graal.nodes.memory.MemoryCheckpoint;
 import com.oracle.graal.nodes.spi.LIRLowerable;
@@ -61,11 +62,36 @@
     protected final ForeignCallDescriptor descriptor;
     protected int bci = BytecodeFrame.UNKNOWN_BCI;
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+    public static boolean intrinsify(GraphBuilderContext b, @InjectedNodeParameter Stamp returnStamp, @InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor,
+                    ValueNode... arguments) {
+        ForeignCallNode node = new ForeignCallNode(foreignCalls, descriptor, arguments);
+        node.setStamp(returnStamp);
+
+        /*
+         * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the case
+         * that the foreign call can deoptimize. As with all deoptimization, we need a state in a
+         * non-intrinsic method.
+         */
+        GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
+        if (nonIntrinsicAncestor != null) {
+            node.setBci(nonIntrinsicAncestor.bci());
+        }
+
+        JavaKind returnKind = returnStamp.getStackKind();
+        if (returnKind == JavaKind.Void) {
+            b.add(node);
+        } else {
+            b.addPush(returnKind, node);
+        }
+
+        return true;
+    }
+
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
         this(TYPE, foreignCalls, descriptor, arguments);
     }
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
         super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
@@ -73,7 +99,7 @@
         assert descriptor.getArgumentTypes().length == this.arguments.size() : "wrong number of arguments to " + this;
     }
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
         super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this);
         this.descriptor = descriptor;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCopyNode.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCopyNode.java	Tue Nov 24 19:31:56 2015 +0100
@@ -25,93 +25,24 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.LocationIdentity;
 
-import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.graph.NodeClass;
-import com.oracle.graal.nodeinfo.InputType;
-import com.oracle.graal.nodeinfo.NodeInfo;
-import com.oracle.graal.nodes.FixedWithNextNode;
-import com.oracle.graal.nodes.FrameState;
-import com.oracle.graal.nodes.StateSplit;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 
 /**
  * Copy a value at a location specified as an offset relative to a source object to another location
  * specified as an offset relative to destination object. No null checks are performed.
- *
- * This node must be replaced during processing of node intrinsics with an {@link UnsafeLoadNode}
- * and {@link UnsafeStoreNode} pair.
  */
-@NodeInfo
-public final class UnsafeCopyNode extends FixedWithNextNode implements StateSplit {
-
-    public static final NodeClass<UnsafeCopyNode> TYPE = NodeClass.create(UnsafeCopyNode.class);
-    @Input ValueNode sourceObject;
-    @Input ValueNode destinationObject;
-    @Input ValueNode sourceOffset;
-    @Input ValueNode destinationOffset;
-    protected final JavaKind accessKind;
-    protected final LocationIdentity locationIdentity;
-    @OptionalInput(InputType.State) FrameState stateAfter;
-
-    public UnsafeCopyNode(ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, JavaKind accessKind, LocationIdentity locationIdentity) {
-        this(sourceObject, sourceOffset, destinationObject, destinationOffset, accessKind, locationIdentity, null);
-    }
-
-    public UnsafeCopyNode(ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, JavaKind accessKind, LocationIdentity locationIdentity,
-                    FrameState stateAfter) {
-        super(TYPE, StampFactory.forVoid());
-        this.sourceObject = sourceObject;
-        this.sourceOffset = sourceOffset;
-        this.destinationObject = destinationObject;
-        this.destinationOffset = destinationOffset;
-        this.accessKind = accessKind;
-        this.locationIdentity = locationIdentity;
-        this.stateAfter = stateAfter;
-        assert accessKind != JavaKind.Void && accessKind != JavaKind.Illegal;
-    }
-
-    public ValueNode sourceObject() {
-        return sourceObject;
-    }
+public final class UnsafeCopyNode {
 
-    public ValueNode destinationObject() {
-        return destinationObject;
-    }
-
-    public LocationIdentity getLocationIdentity() {
-        return locationIdentity;
-    }
-
-    public ValueNode sourceOffset() {
-        return sourceOffset;
-    }
-
-    public ValueNode destinationOffset() {
-        return destinationOffset;
-    }
-
-    public JavaKind accessKind() {
-        return accessKind;
-    }
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
+    public static boolean intrinsify(GraphBuilderContext b, ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, JavaKind accessKind,
+                    LocationIdentity locationIdentity) {
+        UnsafeLoadNode value = b.add(new UnsafeLoadNode(sourceObject, sourceOffset, accessKind, locationIdentity));
+        b.add(new UnsafeStoreNode(destinationObject, destinationOffset, value, accessKind, locationIdentity));
         return true;
     }
 
-    public FrameState getState() {
-        return stateAfter;
-    }
-
     @NodeIntrinsic
     public static native void copy(Object srcObject, long srcOffset, Object destObject, long destOffset, @ConstantNodeParameter JavaKind kind, @ConstantNodeParameter LocationIdentity locationIdentity);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GeneratedInvocationPlugin.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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.graphbuilderconf;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.nodes.ValueNode;
+
+public abstract class GeneratedInvocationPlugin implements InvocationPlugin {
+
+    public abstract boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugins.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugins.java	Tue Nov 24 19:31:56 2015 +0100
@@ -566,7 +566,7 @@
                 assert !p.containsKey(method) : "a plugin is already registered for " + method;
                 p = p.parent;
             }
-            if (plugin instanceof ForeignCallPlugin) {
+            if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
                 return true;
             }
             if (plugin instanceof MethodSubstitutionPlugin) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 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.graphbuilderconf;
+
+import com.oracle.graal.compiler.common.type.Stamp;
+
+public interface NodeIntrinsicPluginFactory {
+
+    public interface InjectionProvider {
+
+        <T> T getInjectedArgument(Class<T> type);
+
+        Stamp getReturnStamp(Class<?> type);
+    }
+
+    void registerPlugin(InvocationPlugins plugins, InjectionProvider injection);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java	Tue Nov 24 19:31:56 2015 +0100
@@ -49,7 +49,7 @@
 
     public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
 
-    private WriteNode(ValueNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
+    protected WriteNode(ValueNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
         this((AddressNode) address, location, value, barrierType);
     }
 
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathSubstitutions.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathSubstitutions.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -114,9 +114,9 @@
         }
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = ForeignCallNode.class)
     private static native double callDouble1(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
 
-    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = ForeignCallNode.class)
     private static native double callDouble2(@ConstantNodeParameter ForeignCallDescriptor descriptor, double a, double b);
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Tue Nov 24 19:31:56 2015 +0100
@@ -35,6 +35,7 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.PiNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.runtime.RuntimeProvider;
 
@@ -43,6 +44,14 @@
  */
 public class ReplacementsParseTest extends GraalCompilerTest {
 
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factory, jvmci service providers don't work from unit tests
+        new NodeIntrinsicFactory_ReplacementsParseTest_TestMethodsSubstitutions_asNonNullStringIntrinsic_2bfccb54().registerPlugin(ret.getInvocationPlugins(), null);
+        return ret;
+    }
+
     private static final Object THROW_EXCEPTION_MARKER = new Object() {
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 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
@@ -46,12 +46,13 @@
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.memory.MemoryNode;
 
 public class SubstitutionsTest extends GraalCompilerTest {
 
     @NodeInfo(allowedUsageTypes = {Memory})
-    private static class TestMemory extends FixedWithNextNode implements MemoryNode {
+    static class TestMemory extends FixedWithNextNode implements MemoryNode {
         private static final NodeClass<TestMemory> TYPE = NodeClass.create(TestMemory.class);
 
         public TestMemory() {
@@ -63,7 +64,7 @@
     }
 
     @NodeInfo(allowedUsageTypes = {Guard})
-    private static class TestGuard extends FloatingNode implements GuardingNode {
+    static class TestGuard extends FloatingNode implements GuardingNode {
         private static final NodeClass<TestGuard> TYPE = NodeClass.create(TestGuard.class);
 
         @Input(Memory) MemoryNode memory;
@@ -78,7 +79,7 @@
     }
 
     @NodeInfo
-    private static class TestValue extends FloatingNode {
+    static class TestValue extends FloatingNode {
         private static final NodeClass<TestValue> TYPE = NodeClass.create(TestValue.class);
 
         @Input(Guard) GuardingNode guard;
@@ -124,6 +125,16 @@
     }
 
     @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factories, jvmci service providers don't work from unit tests
+        new NodeIntrinsicFactory_SubstitutionsTest_TestGuard_guard_1c2b7e8f().registerPlugin(ret.getInvocationPlugins(), null);
+        new NodeIntrinsicFactory_SubstitutionsTest_TestMemory_memory().registerPlugin(ret.getInvocationPlugins(), null);
+        new NodeIntrinsicFactory_SubstitutionsTest_TestValue_value_a22f0f5f().registerPlugin(ret.getInvocationPlugins(), null);
+        return ret;
+    }
+
+    @Override
     protected boolean checkHighTierGraph(StructuredGraph graph) {
         // Check that the graph contains the expected test nodes.
         NodeIterable<ReturnNode> retNodes = graph.getNodes().filter(ReturnNode.class);
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,9 +26,18 @@
 import java.util.List;
 
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
 import javax.tools.Diagnostic.Kind;
 
 /**
@@ -96,6 +105,81 @@
         return cur;
     }
 
+    private static void getSignatureName(StringBuilder ret, Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing.getKind() == ElementKind.PACKAGE) {
+            ret.append(((PackageElement) enclosing).getQualifiedName().toString().replace('.', '/'));
+            ret.append('/');
+        } else {
+            getSignatureName(ret, enclosing);
+            ret.append('$');
+        }
+        ret.append(element.getSimpleName());
+    }
+
+    private static void getSignatureString(StringBuilder ret, TypeMirror type) {
+        switch (type.getKind()) {
+            case ARRAY:
+                ret.append('[');
+                getSignatureString(ret, ((ArrayType) type).getComponentType());
+                break;
+            case BOOLEAN:
+                ret.append('Z');
+                break;
+            case BYTE:
+                ret.append('B');
+                break;
+            case SHORT:
+                ret.append('S');
+                break;
+            case CHAR:
+                ret.append('C');
+                break;
+            case INT:
+                ret.append('I');
+                break;
+            case LONG:
+                ret.append('J');
+                break;
+            case FLOAT:
+                ret.append('F');
+                break;
+            case DOUBLE:
+                ret.append('D');
+                break;
+            case VOID:
+                ret.append('V');
+                break;
+            case DECLARED:
+                ret.append('L');
+                getSignatureName(ret, ((DeclaredType) type).asElement());
+                ret.append(';');
+                break;
+            case TYPEVAR:
+                getSignatureString(ret, ((TypeVariable) type).getUpperBound());
+                break;
+            case WILDCARD:
+                getSignatureString(ret, ((WildcardType) type).getExtendsBound());
+                break;
+            case INTERSECTION:
+                ret.append("Ljava/lang/Object;");
+                break;
+            default:
+                throw new IllegalArgumentException(type.toString());
+        }
+    }
+
+    public static String toSignature(ExecutableElement intrinsicMethod) {
+        StringBuilder ret = new StringBuilder();
+        ret.append('(');
+        for (VariableElement param : intrinsicMethod.getParameters()) {
+            getSignatureString(ret, param.asType());
+        }
+        ret.append(')');
+        getSignatureString(ret, intrinsicMethod.getReturnType());
+        return ret.toString();
+    }
+
     public int getParameterCount(boolean withReceiver) {
         return arguments.size() + (withReceiver ? 1 : 0);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/FoldPluginGenerator.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 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.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import com.oracle.graal.api.replacements.Fold;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@link Fold} methods.
+ */
+public class FoldPluginGenerator extends PluginGenerator {
+
+    private class FoldVerifier extends AbstractVerifier {
+
+        public FoldVerifier(ProcessingEnvironment env) {
+            super(env);
+        }
+
+        @Override
+        public void verify(Element element, AnnotationMirror annotation) {
+            if (element.getKind() != ElementKind.METHOD) {
+                assert false : "Element is guaranteed to be a method.";
+                return;
+            }
+
+            ExecutableElement intrinsicMethod = (ExecutableElement) element;
+            if (intrinsicMethod.getModifiers().contains(Modifier.PRIVATE)) {
+                env.getMessager().printMessage(Kind.ERROR, "@Fold method can not be private.", element);
+            } else {
+                FoldPluginGenerator.this.createPluginFactory(intrinsicMethod, null, null);
+            }
+        }
+
+        @Override
+        public Class<? extends Annotation> getAnnotationClass() {
+            return Fold.class;
+        }
+    }
+
+    private TypeMirror stringType() {
+        return env.getElementUtils().getTypeElement("java.lang.String").asType();
+    }
+
+    public FoldPluginGenerator(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    public AbstractVerifier getVerifier() {
+        return new FoldVerifier(env);
+    }
+
+    @Override
+    protected String getBaseName() {
+        return "FoldFactory";
+    }
+
+    @Override
+    protected void createImports(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement targetMethod) {
+        out.printf("import jdk.vm.ci.meta.JavaConstant;\n");
+        out.printf("import jdk.vm.ci.meta.JavaKind;\n");
+        out.printf("import com.oracle.graal.nodes.ConstantNode;\n");
+        super.createImports(out, intrinsicMethod, targetMethod);
+    }
+
+    @Override
+    protected InjectedDependencies createExecute(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+        InjectedDependencies deps = new InjectedDependencies();
+        List<? extends VariableElement> params = intrinsicMethod.getParameters();
+
+        int idx = 0;
+        for (VariableElement param : params) {
+            constantArgument(out, deps, idx, param.asType(), idx);
+            idx++;
+        }
+
+        if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
+            out.printf("            @SuppressWarnings(\"deprecation\")\n");
+        }
+        out.printf("            %s result = %s.%s(", intrinsicMethod.getReturnType(), intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
+        if (idx > 0) {
+            out.printf("_arg0");
+            for (int i = 1; i < idx; i++) {
+                out.printf(", _arg%d", i);
+            }
+        }
+        out.printf(");\n");
+
+        TypeMirror returnType = intrinsicMethod.getReturnType();
+        switch (returnType.getKind()) {
+            case BOOLEAN:
+                out.printf("            JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n");
+                break;
+            case BYTE:
+            case SHORT:
+            case CHAR:
+            case INT:
+                out.printf("            JavaConstant constant = JavaConstant.forInt(result);\n");
+                break;
+            case LONG:
+                out.printf("            JavaConstant constant = JavaConstant.forLong(result);\n");
+                break;
+            case FLOAT:
+                out.printf("            JavaConstant constant = JavaConstant.forFloat(result);\n");
+                break;
+            case DOUBLE:
+                out.printf("            JavaConstant constant = JavaConstant.forDouble(result);\n");
+                break;
+            case ARRAY:
+            case TYPEVAR:
+            case DECLARED:
+                if (returnType.equals(stringType())) {
+                    out.printf("            JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION));
+                } else {
+                    out.printf("            JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION));
+                }
+                break;
+            default:
+                throw new IllegalArgumentException(returnType.toString());
+        }
+
+        out.printf("            ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH));
+        out.printf("            b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod).name());
+        out.printf("            return true;\n");
+
+        return deps;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/InjectedDependencies.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 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.replacements.verifier;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+import com.oracle.graal.replacements.verifier.InjectedDependencies.Dependency;
+
+public class InjectedDependencies implements Iterable<Dependency> {
+
+    public abstract static class Dependency {
+
+        public final String name;
+        public final String type;
+
+        private Dependency(String name, String type) {
+            this.name = name;
+            this.type = type;
+        }
+
+        public abstract String inject(ExecutableElement inject);
+    }
+
+    private static final class InjectedDependency extends Dependency {
+
+        private InjectedDependency(String name, String type) {
+            super(name, type);
+        }
+
+        @Override
+        public String inject(ExecutableElement inject) {
+            return String.format("injection.getInjectedArgument(%s.class)", type);
+        }
+    }
+
+    private static final class StampDependency extends Dependency {
+
+        private StampDependency() {
+            super("returnStamp", "com.oracle.graal.compiler.common.type.Stamp");
+        }
+
+        @Override
+        public String inject(ExecutableElement inject) {
+            return String.format("injection.getReturnStamp(%s.class)", NodeIntrinsicPluginGenerator.getErasedType(inject.getReturnType()));
+        }
+    }
+
+    public enum WellKnownDependency {
+        CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"),
+        META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"),
+        RETURN_STAMP(new StampDependency()),
+        SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "com.oracle.graal.api.replacements.SnippetReflectionProvider")),
+        STAMP_PROVIDER("b.getStampProvider()", "com.oracle.graal.nodes.spi.StampProvider"),
+        STRUCTURED_GRAPH("b.getGraph()", "com.oracle.graal.nodes.StructuredGraph");
+
+        private final String expr;
+        private final String type;
+        private final Dependency generateMember;
+
+        private WellKnownDependency(String expr, String type) {
+            this.expr = expr;
+            this.type = type;
+            this.generateMember = null;
+        }
+
+        private WellKnownDependency(Dependency generateMember) {
+            this.expr = generateMember.name;
+            this.type = generateMember.type;
+            this.generateMember = generateMember;
+        }
+
+        private TypeMirror getType(ProcessingEnvironment env) {
+            return env.getElementUtils().getTypeElement(type).asType();
+        }
+    }
+
+    private final HashMap<String, Dependency> deps;
+
+    public InjectedDependencies() {
+        deps = new HashMap<>();
+    }
+
+    public String use(WellKnownDependency wellKnown) {
+        if (wellKnown.generateMember != null) {
+            deps.put(wellKnown.type, wellKnown.generateMember);
+        }
+        return wellKnown.expr;
+    }
+
+    public String use(ProcessingEnvironment env, DeclaredType type) {
+        for (WellKnownDependency wellKnown : WellKnownDependency.values()) {
+            if (env.getTypeUtils().isAssignable(wellKnown.getType(env), type)) {
+                return use(wellKnown);
+            }
+        }
+
+        String typeName = type.toString();
+        Dependency ret = deps.get(typeName);
+        if (ret == null) {
+            ret = new InjectedDependency("injected" + type.asElement().getSimpleName(), typeName);
+            deps.put(typeName, ret);
+        }
+        return ret.name;
+    }
+
+    public Iterator<Dependency> iterator() {
+        return deps.values().iterator();
+    }
+
+    public boolean isEmpty() {
+        return deps.isEmpty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicPluginGenerator.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 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.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.InjectedNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@link NodeIntrinsic} methods.
+ */
+public class NodeIntrinsicPluginGenerator extends PluginGenerator {
+
+    public NodeIntrinsicPluginGenerator(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    private TypeMirror valueNodeType() {
+        return env.getElementUtils().getTypeElement("com.oracle.graal.nodes.ValueNode").asType();
+    }
+
+    @Override
+    protected String getBaseName() {
+        return "NodeIntrinsicFactory";
+    }
+
+    @Override
+    protected void createImports(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement targetMethod) {
+        if (targetMethod.getKind() == ElementKind.CONSTRUCTOR && getReturnKind(intrinsicMethod) != JavaKind.Void) {
+            out.printf("import jdk.vm.ci.meta.JavaKind;\n");
+        }
+        super.createImports(out, intrinsicMethod, targetMethod);
+    }
+
+    @Override
+    protected InjectedDependencies createExecute(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+        InjectedDependencies deps = new InjectedDependencies();
+
+        List<? extends VariableElement> params = constructor.getParameters();
+
+        boolean customFactory = constructor.getKind() != ElementKind.CONSTRUCTOR;
+        int idx = customFactory ? 1 : 0;
+        for (; idx < params.size(); idx++) {
+            VariableElement param = params.get(idx);
+            if (param.getAnnotation(InjectedNodeParameter.class) == null) {
+                break;
+            }
+
+            out.printf("            %s _arg%d = %s;\n", param.asType(), idx, deps.use(env, (DeclaredType) param.asType()));
+        }
+
+        for (int i = 0; i < signature.length; i++, idx++) {
+            if (intrinsicMethod.getParameters().get(i).getAnnotation(ConstantNodeParameter.class) != null) {
+                constantArgument(out, deps, idx, signature[i], i);
+            } else {
+                if (signature[i].equals(valueNodeType())) {
+                    out.printf("            ValueNode _arg%d = args[%d];\n", idx, i);
+                } else {
+                    out.printf("            %s _arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i);
+                }
+            }
+        }
+
+        if (customFactory) {
+            out.printf("            return %s.%s(b", constructor.getEnclosingElement(), constructor.getSimpleName());
+            for (int i = 1; i < idx; i++) {
+                out.printf(", _arg%d", i);
+            }
+            out.printf(");\n");
+
+            if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
+                env.getMessager().printMessage(Kind.WARNING, "Ignoring setStampFromReturnType because a custom 'intrinsify' method is used.", intrinsicMethod);
+            }
+        } else {
+            out.printf("            %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
+            if (idx > 0) {
+                out.printf("_arg0");
+                for (int i = 1; i < idx; i++) {
+                    out.printf(", _arg%d", i);
+                }
+            }
+            out.printf(");\n");
+
+            if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
+                out.printf("            node.setStamp(%s);\n", deps.use(WellKnownDependency.RETURN_STAMP));
+            }
+
+            JavaKind returnKind = getReturnKind(intrinsicMethod);
+            if (returnKind == JavaKind.Void) {
+                out.printf("            b.add(node);\n");
+            } else {
+                out.printf("            b.addPush(JavaKind.%s, node);\n", returnKind.name());
+            }
+            out.printf("            return true;\n");
+        }
+
+        return deps;
+    }
+}
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Tue Nov 24 19:31:56 2015 +0100
@@ -73,8 +73,15 @@
         return env.getElementUtils().getTypeElement("com.oracle.graal.nodeinfo.StructuralInput").asType();
     }
 
+    private TypeMirror graphBuilderContextType() {
+        return env.getElementUtils().getTypeElement("com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext").asType();
+    }
+
+    private final NodeIntrinsicPluginGenerator factoryGen;
+
     public NodeIntrinsicVerifier(ProcessingEnvironment env) {
         super(env);
+        factoryGen = new NodeIntrinsicPluginGenerator(env);
     }
 
     @Override
@@ -114,20 +121,28 @@
             env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation);
         }
 
-        if (isNodeType(nodeClass)) {
-            if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
-                env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
+        TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
+        ExecutableElement custom = findCustomIntrinsifyMethod(nodeClass, constructorSignature);
+        if (custom != null) {
+            factoryGen.createPluginFactory(intrinsicMethod, custom, constructorSignature);
+        } else {
+            if (isNodeType(nodeClass)) {
+                if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
+                    env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
+                } else {
+                    TypeMirror ret = intrinsicMethod.getReturnType();
+                    if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
+                        checkInputType(nodeClass, ret, element, annotation);
+                    }
+
+                    ExecutableElement constructor = findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
+                    if (constructor != null) {
+                        factoryGen.createPluginFactory(intrinsicMethod, constructor, constructorSignature);
+                    }
+                }
             } else {
-                TypeMirror ret = intrinsicMethod.getReturnType();
-                if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
-                    checkInputType(nodeClass, ret, element, annotation);
-                }
-
-                TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
-                findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
+                env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is not a Node subclass.", nodeClass.getSimpleName()), element, annotation);
             }
-        } else {
-            env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is not a Node subclass.", nodeClass.getSimpleName()), element, annotation);
         }
     }
 
@@ -185,47 +200,18 @@
         return parameters;
     }
 
-    private void findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) {
+    private ExecutableElement findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) {
         List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements());
         List<String> failureReasons = new ArrayList<>();
 
-        nextConstructor: for (ExecutableElement constructor : constructors) {
-            int sIdx = 0;
-            int cIdx = 0;
-            while (cIdx < constructor.getParameters().size()) {
-                VariableElement parameter = constructor.getParameters().get(cIdx++);
-                if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
-                    // skip injected parameters
-                    continue;
-                }
-
-                TypeMirror paramType = parameter.asType();
-                if (cIdx == constructor.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
-                    // last argument of constructor is varargs, match remaining intrinsic arguments
-                    TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
-                    while (sIdx < signature.length) {
-                        if (!isTypeCompatible(varargsType, signature[sIdx++])) {
-                            failureReasons.add(String.format("Constructor %s failed because the types of argument %d are incompatible: %s != %s", constructor, sIdx, varargsType, signature[sIdx - 1]));
-                            continue nextConstructor;
-                        }
-                    }
-                } else if (sIdx >= signature.length) {
-                    // too many arguments in intrinsic method
-                    failureReasons.add(String.format("Too many arguments for %s", constructor));
-                    continue nextConstructor;
-                } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
-                    failureReasons.add(String.format("Constructor %s failed because the types of argument %d are incompatible: %s != %s", constructor, sIdx, paramType, signature[sIdx - 1]));
-                    continue nextConstructor;
-                }
+        for (ExecutableElement constructor : constructors) {
+            String failureReason = matchSignature(false, constructor, signature);
+            if (failureReason == null) {
+                // found
+                return constructor;
             }
 
-            if (sIdx == signature.length) {
-                // found
-                return;
-            }
-
-            // too many arguments in constructor
-            failureReasons.add(String.format("Not enough arguments for %s", constructor));
+            failureReasons.add(failureReason);
         }
 
         // not found
@@ -236,6 +222,70 @@
                 env.getMessager().printMessage(Kind.ERROR, reason, intrinsicMethod, intrinsicAnnotation);
             }
         }
+
+        return null;
+    }
+
+    private ExecutableElement findCustomIntrinsifyMethod(TypeElement nodeClass, TypeMirror[] signature) {
+        List<ExecutableElement> methods = ElementFilter.methodsIn(nodeClass.getEnclosedElements());
+        for (ExecutableElement method : methods) {
+            if (!method.getSimpleName().toString().equals("intrinsify")) {
+                continue;
+            }
+
+            if (method.getParameters().isEmpty()) {
+                continue;
+            }
+
+            VariableElement firstArg = method.getParameters().get(0);
+            if (!isTypeCompatible(firstArg.asType(), graphBuilderContextType())) {
+                continue;
+            }
+
+            String failureReason = matchSignature(true, method, signature);
+            if (failureReason == null) {
+                // found
+                return method;
+            }
+        }
+
+        return null;
+    }
+
+    private String matchSignature(boolean skipFirst, ExecutableElement method, TypeMirror[] signature) {
+        int sIdx = 0;
+        int cIdx = skipFirst ? 1 : 0;
+        while (cIdx < method.getParameters().size()) {
+            VariableElement parameter = method.getParameters().get(cIdx++);
+            if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
+                // skip injected parameters
+                continue;
+            }
+
+            TypeMirror paramType = parameter.asType();
+            if (cIdx == method.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
+                // last argument of constructor is varargs, match remaining intrinsic arguments
+                TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
+                while (sIdx < signature.length) {
+                    if (!isTypeCompatible(varargsType, signature[sIdx++])) {
+                        return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, varargsType, signature[sIdx - 1]);
+                    }
+                }
+            } else if (sIdx >= signature.length) {
+                // too many arguments in intrinsic method
+                return String.format("Too many arguments for %s", method);
+            } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
+                return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, paramType, signature[sIdx - 1]);
+            }
+        }
+
+        if (sIdx == signature.length) {
+            // found
+            return null;
+        }
+
+        // too many arguments in constructor
+        return String.format("Not enough arguments for %s", method);
     }
 
     private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 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.replacements.verifier;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import com.oracle.graal.replacements.verifier.InjectedDependencies.Dependency;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+public abstract class PluginGenerator {
+
+    protected final ProcessingEnvironment env;
+
+    public PluginGenerator(ProcessingEnvironment env) {
+        this.env = env;
+    }
+
+    private TypeMirror resolvedJavaTypeType() {
+        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
+    }
+
+    private static PackageElement getPackage(Element element) {
+        Element enclosing = element;
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            enclosing = enclosing.getEnclosingElement();
+        }
+        return (PackageElement) enclosing;
+    }
+
+    private static void mkClassName(StringBuilder ret, Element cls) {
+        Element enclosingClass = cls.getEnclosingElement();
+        if (enclosingClass.getKind() == ElementKind.CLASS || enclosingClass.getKind() == ElementKind.INTERFACE) {
+            mkClassName(ret, enclosingClass);
+            ret.append('_');
+        }
+        ret.append(cls.getSimpleName());
+    }
+
+    static String getErasedType(TypeMirror type) {
+        switch (type.getKind()) {
+            case DECLARED:
+                DeclaredType declared = (DeclaredType) type;
+                TypeElement element = (TypeElement) declared.asElement();
+                return element.getQualifiedName().toString();
+            case TYPEVAR:
+                return getErasedType(((TypeVariable) type).getUpperBound());
+            case WILDCARD:
+                return getErasedType(((WildcardType) type).getExtendsBound());
+            case ARRAY:
+                return getErasedType(((ArrayType) type).getComponentType()) + "[]";
+            default:
+                return type.toString();
+        }
+    }
+
+    protected abstract String getBaseName();
+
+    private String mkFactoryClassName(ExecutableElement intrinsicMethod) {
+        StringBuilder ret = new StringBuilder();
+        ret.append(getBaseName());
+        ret.append('_');
+        mkClassName(ret, intrinsicMethod.getEnclosingElement());
+        ret.append('_');
+        ret.append(intrinsicMethod.getSimpleName());
+        if (!intrinsicMethod.getParameters().isEmpty()) {
+            ret.append('_');
+            ret.append(Integer.toHexString(APHotSpotSignature.toSignature(intrinsicMethod).hashCode()));
+        }
+        return ret.toString();
+    }
+
+    void createPluginFactory(ExecutableElement intrinsicMethod, ExecutableElement targetMethod, TypeMirror[] constructorSignature) {
+        Element declaringClass = intrinsicMethod.getEnclosingElement();
+        PackageElement pkg = getPackage(declaringClass);
+
+        String genClassName = mkFactoryClassName(intrinsicMethod);
+
+        try {
+            JavaFileObject factory = env.getFiler().createSourceFile(pkg.getQualifiedName() + "." + genClassName, intrinsicMethod);
+            try (PrintWriter out = new PrintWriter(factory.openWriter())) {
+                out.printf("// CheckStyle: stop header check\n");
+                out.printf("// CheckStyle: stop line length check\n");
+                out.printf("// GENERATED CONTENT - DO NOT EDIT\n");
+                out.printf("package %s;\n", pkg.getQualifiedName());
+                out.printf("\n");
+                createImports(out, intrinsicMethod, targetMethod);
+                out.printf("\n");
+                out.printf("@ServiceProvider(NodeIntrinsicPluginFactory.class)\n");
+                out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName);
+                out.printf("\n");
+                out.printf("    private static final class Plugin extends GeneratedInvocationPlugin {\n");
+                out.printf("\n");
+
+                out.printf("        @Override\n");
+                out.printf("        public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n");
+                out.printf("            if (!b.parsingIntrinsic()) {\n");
+                out.printf("                return false;\n");
+                out.printf("            }\n");
+                InjectedDependencies deps = createExecute(out, intrinsicMethod, targetMethod, constructorSignature);
+                out.printf("        }\n");
+
+                createPrivateMembers(out, intrinsicMethod, deps);
+
+                out.printf("    }\n");
+                out.printf("\n");
+                createPluginFactoryMethod(out, intrinsicMethod, deps);
+                out.printf("}\n");
+            }
+        } catch (IOException e) {
+            env.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
+        }
+    }
+
+    protected abstract InjectedDependencies createExecute(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature);
+
+    protected void createImports(PrintWriter out, @SuppressWarnings("unused") ExecutableElement intrinsicMethod, @SuppressWarnings("unused") ExecutableElement targetMethod) {
+        out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
+        out.printf("import jdk.vm.ci.service.ServiceProvider;\n");
+        out.printf("\n");
+        out.printf("import com.oracle.graal.nodes.ValueNode;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.GeneratedInvocationPlugin;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;\n");
+    }
+
+    private static void createPrivateMembers(PrintWriter out, ExecutableElement intrinsicMethod, InjectedDependencies deps) {
+        if (!deps.isEmpty()) {
+            out.printf("\n");
+            for (Dependency dep : deps) {
+                out.printf("        private final %s %s;\n", dep.type, dep.name);
+            }
+
+            out.printf("\n");
+            out.printf("        private Plugin(InjectionProvider injection) {\n");
+            for (Dependency dep : deps) {
+                out.printf("            this.%s = %s;\n", dep.name, dep.inject(intrinsicMethod));
+            }
+            out.printf("        }\n");
+        }
+    }
+
+    private static void createPluginFactoryMethod(PrintWriter out, ExecutableElement intrinsicMethod, InjectedDependencies deps) {
+        out.printf("    public void registerPlugin(InvocationPlugins plugins, InjectionProvider injection) {\n");
+        out.printf("        Plugin plugin = new Plugin(%s);\n", deps.isEmpty() ? "" : "injection");
+        out.printf("        plugins.register(plugin, %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
+        for (VariableElement arg : intrinsicMethod.getParameters()) {
+            out.printf(", %s.class", getErasedType(arg.asType()));
+        }
+        out.printf(");\n");
+        out.printf("    }\n");
+    }
+
+    protected static JavaKind getReturnKind(ExecutableElement method) {
+        switch (method.getReturnType().getKind()) {
+            case BOOLEAN:
+            case BYTE:
+            case SHORT:
+            case CHAR:
+            case INT:
+                return JavaKind.Int;
+            case LONG:
+                return JavaKind.Long;
+            case FLOAT:
+                return JavaKind.Float;
+            case DOUBLE:
+                return JavaKind.Double;
+            case VOID:
+                return JavaKind.Void;
+            case ARRAY:
+            case TYPEVAR:
+            case DECLARED:
+                return JavaKind.Object;
+            default:
+                throw new IllegalArgumentException(method.getReturnType().toString());
+        }
+    }
+
+    protected void constantArgument(PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) {
+        out.printf("            %s _arg%d;\n", type, argIdx);
+        out.printf("            if (args[%d].isConstant()) {\n", nodeIdx);
+        if (type.equals(resolvedJavaTypeType())) {
+            out.printf("                _arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx);
+        } else {
+            switch (type.getKind()) {
+                case BOOLEAN:
+                    out.printf("                _arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx);
+                    break;
+                case BYTE:
+                    out.printf("                _arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case CHAR:
+                    out.printf("                _arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case SHORT:
+                    out.printf("                _arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case INT:
+                    out.printf("                _arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case LONG:
+                    out.printf("                _arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx);
+                    break;
+                case FLOAT:
+                    out.printf("                _arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx);
+                    break;
+                case DOUBLE:
+                    out.printf("                _arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx);
+                    break;
+                case DECLARED:
+                    out.printf("                _arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), type, nodeIdx);
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+        out.printf("            } else {\n");
+        out.printf("                return false;\n");
+        out.printf("            }\n");
+    }
+}
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -84,6 +84,7 @@
             verifiers.add(new ClassSubstitutionVerifier(this.processingEnv));
             verifiers.add(new MethodSubstitutionVerifier(this.processingEnv));
             verifiers.add(new NodeIntrinsicVerifier(this.processingEnv));
+            verifiers.add(new FoldPluginGenerator(this.processingEnv).getVerifier());
         }
         return verifiers;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsicFactory.java	Tue Nov 24 19:31:56 2015 +0100
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 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.replacements;
+
+import java.lang.reflect.Array;
+import java.util.List;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+
+@NodeInfo
+public final class NodeIntrinsicFactory extends FixedWithNextNode {
+
+    public static final NodeClass<NodeIntrinsicFactory> TYPE = NodeClass.create(NodeIntrinsicFactory.class);
+
+    public static final Object GRAPH_MARKER = new Object();
+
+    private final ResolvedJavaMethod constructor;
+    private final boolean setStampFromReturnType;
+
+    private final Object[] injectedArguments;
+
+    private final Class<?>[] argumentTypes;
+    @Input NodeInputList<ValueNode> arguments;
+
+    private final Class<?> varargsType;
+    @Input NodeInputList<ValueNode> varargs;
+
+    public NodeIntrinsicFactory(Stamp stamp, ResolvedJavaMethod constructor, boolean setStampFromReturnType, Object[] injectedArguments, Class<?>[] argumentTypes, List<ValueNode> arguments) {
+        this(stamp, constructor, setStampFromReturnType, injectedArguments, argumentTypes, arguments, null, null);
+    }
+
+    public NodeIntrinsicFactory(Stamp stamp, ResolvedJavaMethod constructor, boolean setStampFromReturnType, Object[] injectedArguments, Class<?>[] argumentTypes, List<ValueNode> arguments,
+                    Class<?> varargsType, List<ValueNode> varargs) {
+        super(TYPE, stamp);
+
+        this.constructor = constructor;
+        this.setStampFromReturnType = setStampFromReturnType;
+
+        this.injectedArguments = injectedArguments;
+
+        this.argumentTypes = argumentTypes;
+        this.arguments = new NodeInputList<>(this, arguments);
+
+        this.varargsType = varargsType;
+        if (varargs == null) {
+            this.varargs = new NodeInputList<>(this);
+        } else {
+            this.varargs = new NodeInputList<>(this, varargs);
+        }
+    }
+
+    private static Object mkConstArgument(Class<?> argType, Constant constant, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection) {
+        if (argType == ResolvedJavaType.class) {
+            ResolvedJavaType type = constantReflection.asJavaType(constant);
+            assert type != null;
+            return type;
+        } else {
+            JavaConstant javaConstant = (JavaConstant) constant;
+            switch (JavaKind.fromJavaClass(argType)) {
+                case Boolean:
+                    return Boolean.valueOf(javaConstant.asInt() != 0);
+                case Byte:
+                    return Byte.valueOf((byte) javaConstant.asInt());
+                case Short:
+                    return Short.valueOf((short) javaConstant.asInt());
+                case Char:
+                    return Character.valueOf((char) javaConstant.asInt());
+                case Object:
+                    return snippetReflection.asObject(argType, javaConstant);
+                default:
+                    return javaConstant.asBoxedPrimitive();
+            }
+        }
+    }
+
+    public ValueNode intrinsify(StructuredGraph graph, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection) {
+        int totalArgCount = arguments.count();
+        if (injectedArguments != null) {
+            totalArgCount += injectedArguments.length;
+        }
+        if (varargsType != null) {
+            totalArgCount++;
+        }
+
+        Object[] args = new Object[totalArgCount];
+        int idx = 0;
+
+        if (injectedArguments != null) {
+            for (int i = 0; i < injectedArguments.length; i++) {
+                if (injectedArguments[i] == GRAPH_MARKER) {
+                    args[idx++] = graph;
+                } else {
+                    args[idx++] = injectedArguments[i];
+                }
+            }
+        }
+
+        for (int i = 0; i < arguments.size(); i++) {
+            ValueNode node = arguments.get(i);
+            if (argumentTypes[i] == ValueNode.class) {
+                args[idx++] = node;
+            } else {
+                if (!node.isConstant()) {
+                    return null;
+                }
+
+                args[idx++] = mkConstArgument(argumentTypes[i], node.asConstant(), constantReflection, snippetReflection);
+            }
+        }
+
+        if (varargsType != null) {
+            if (varargsType == ValueNode.class) {
+                args[idx++] = varargs.toArray(new ValueNode[0]);
+            } else {
+                Object array = Array.newInstance(varargsType, varargs.size());
+                args[idx++] = array;
+
+                for (int i = 0; i < varargs.size(); i++) {
+                    ValueNode node = varargs.get(i);
+                    if (!node.isConstant()) {
+                        return null;
+                    }
+
+                    Object arg = mkConstArgument(varargsType, node.asConstant(), constantReflection, snippetReflection);
+                    if (varargsType.isPrimitive()) {
+                        Array.set(array, i, arg);
+                    } else {
+                        ((Object[]) array)[i] = arg;
+                    }
+                }
+            }
+        }
+
+        assert idx == totalArgCount;
+
+        ValueNode node = (ValueNode) snippetReflection.invoke(constructor, null, args);
+        if (setStampFromReturnType) {
+            node.setStamp(this.stamp());
+        }
+        return node;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Nov 24 19:31:56 2015 +0100
@@ -22,15 +22,14 @@
  */
 package com.oracle.graal.replacements;
 
-import static jdk.vm.ci.meta.MetaUtil.resolveJavaTypes;
-
-import java.lang.reflect.Array;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
@@ -39,6 +38,7 @@
 import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
 
 import com.oracle.graal.api.replacements.Fold;
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
@@ -65,32 +65,65 @@
 import com.oracle.graal.nodes.extended.UnboxNode;
 import com.oracle.graal.nodes.extended.UnsafeStoreNode;
 import com.oracle.graal.nodes.extended.ValueAnchorNode;
+import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory.InjectionProvider;
 import com.oracle.graal.nodes.java.CheckCastNode;
 import com.oracle.graal.nodes.java.LoadFieldNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.spi.StampProvider;
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.phases.Phase;
+import com.oracle.graal.word.WordTypes;
 
 /**
  * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with
  * {@link Fold} with the result of invoking the annotated method via reflection.
  */
-public class NodeIntrinsificationPhase extends Phase {
+public class NodeIntrinsificationPhase extends Phase implements InjectionProvider {
 
     private final MetaAccessProvider metaAccess;
     private final ConstantReflectionProvider constantReflection;
     private final SnippetReflectionProvider snippetReflection;
     private final ForeignCallsProvider foreignCalls;
     private final StampProvider stampProvider;
+    private final WordTypes wordTypes;
 
     public NodeIntrinsificationPhase(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls,
-                    StampProvider stampProvider) {
+                    StampProvider stampProvider, WordTypes wordTypes) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
         this.snippetReflection = snippetReflection;
         this.foreignCalls = foreignCalls;
         this.stampProvider = stampProvider;
+        this.wordTypes = wordTypes;
+    }
+
+    @Override
+    public Stamp getReturnStamp(Class<?> type) {
+        JavaKind kind = JavaKind.fromJavaClass(type);
+        if (kind == JavaKind.Object) {
+            ResolvedJavaType returnType = metaAccess.lookupJavaType(type);
+            if (wordTypes.isWord(returnType)) {
+                return wordTypes.getWordStamp(returnType);
+            } else {
+                return StampFactory.declared(returnType);
+            }
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    @Override
+    public <T> T getInjectedArgument(Class<T> type) {
+        T injected = snippetReflection.getInjectedNodeIntrinsicParameter(type);
+        if (injected != null) {
+            return injected;
+        } else if (type.equals(ForeignCallsProvider.class)) {
+            return type.cast(foreignCalls);
+        } else if (type.equals(SnippetReflectionProvider.class)) {
+            return type.cast(snippetReflection);
+        } else {
+            throw new JVMCIError("Cannot handle injected argument of type %s.", type.getName());
+        }
     }
 
     @Override
@@ -107,7 +140,6 @@
 
     protected boolean tryIntrinsify(MethodCallTargetNode methodCallTargetNode, List<Node> cleanUpReturnList) {
         ResolvedJavaMethod target = methodCallTargetNode.targetMethod();
-        ResolvedJavaType declaringClass = target.getDeclaringClass();
         StructuredGraph graph = methodCallTargetNode.graph();
 
         NodeIntrinsic intrinsic = getIntrinsic(target);
@@ -125,8 +157,7 @@
             // Clean up checkcast instructions inserted by javac if the return type is generic.
             cleanUpReturnList.add(newInstance);
         } else if (isFoldable(target)) {
-            ResolvedJavaType[] parameterTypes = resolveJavaTypes(target.toParameterTypes(), declaringClass);
-            JavaConstant constant = tryFold(methodCallTargetNode.arguments(), parameterTypes, target);
+            JavaConstant constant = tryFold(methodCallTargetNode.arguments(), target);
             if (constant != null && constant.equals(COULD_NOT_FOLD)) {
                 return false;
             }
@@ -153,8 +184,8 @@
         }
     };
 
-    public JavaConstant tryFold(List<ValueNode> args, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target) {
-        JavaConstant[] reflectArgs = (JavaConstant[]) prepareArguments(args, parameterTypes, target, true);
+    public JavaConstant tryFold(List<ValueNode> args, ResolvedJavaMethod target) {
+        JavaConstant[] reflectArgs = prepareFoldingArguments(args);
         if (reflectArgs == null) {
             return COULD_NOT_FOLD;
         }
@@ -169,6 +200,26 @@
     }
 
     /**
+     * Select a constructor and prepare the injected arguments for intrinsification of a call to a
+     * {@link NodeIntrinsic} annotated method.
+     *
+     * @param arguments the arguments of the call
+     * @param stamp the stamp to use for the returned node
+     * @param method the method annotated with {@link NodeIntrinsic}
+     * @return an {@link NodeIntrinsicFactory} that can be used to
+     *         {@link NodeIntrinsicFactory#intrinsify intrinsify} the call
+     */
+    public NodeIntrinsicFactory createIntrinsicFactory(List<ValueNode> arguments, Stamp stamp, ResolvedJavaMethod method, NodeIntrinsic intrinsic) {
+        assert method.getAnnotation(Fold.class) == null;
+        assert method.isStatic() : "node intrinsic must be static: " + method;
+
+        Class<? extends ValueNode> nodeClass = getNodeClass(method, intrinsic);
+        Class<?>[] parameterTypes = prepareIntrinsicArgumentTypes(method);
+
+        return createIntrinsicFactory(nodeClass, parameterTypes, arguments, stamp, intrinsic.setStampFromReturnType());
+    }
+
+    /**
      * Attempts to create a node to replace a call to a {@link NodeIntrinsic} annotated method.
      *
      * @param arguments the arguments of the call
@@ -179,20 +230,8 @@
      *         representing the intrinsic
      */
     public ValueNode createIntrinsicNode(List<ValueNode> arguments, Stamp stamp, ResolvedJavaMethod method, StructuredGraph graph, NodeIntrinsic intrinsic) {
-        assert method.getAnnotation(Fold.class) == null;
-        assert method.isStatic() : "node intrinsic must be static: " + method;
-
-        ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
-
-        // Prepare the arguments for the reflective constructor call on the node class.
-        Object[] nodeConstructorArguments = prepareArguments(arguments, parameterTypes, method, false);
-        if (nodeConstructorArguments == null) {
-            return null;
-        }
-
-        // Create the new node instance.
-        ResolvedJavaType c = getNodeClass(method, intrinsic);
-        return createNodeInstance(graph, c, parameterTypes, stamp, intrinsic.setStampFromReturnType(), nodeConstructorArguments);
+        NodeIntrinsicFactory factory = createIntrinsicFactory(arguments, stamp, method, intrinsic);
+        return factory.intrinsify(graph, constantReflection, snippetReflection);
     }
 
     /**
@@ -209,185 +248,183 @@
         return method.getAnnotation(Fold.class) != null;
     }
 
-    /**
-     * Converts the arguments of an invoke node to object values suitable for use as the arguments
-     * to a reflective invocation of a Java constructor or method.
-     *
-     * @param folding specifies if the invocation is for handling a {@link Fold} annotation
-     * @return the arguments for the reflective invocation or null if an argument of {@code invoke}
-     *         that is expected to be constant isn't
-     */
-    private Object[] prepareArguments(List<ValueNode> arguments, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
-        Object[] reflectionCallArguments = folding ? new JavaConstant[arguments.size()] : new Object[arguments.size()];
-        for (int i = 0; i < reflectionCallArguments.length; ++i) {
+    private Class<?>[] prepareIntrinsicArgumentTypes(ResolvedJavaMethod target) {
+        Signature signature = target.getSignature();
+        boolean hasReceiver = !target.isStatic();
+
+        Class<?>[] argumentTypes = new Class<?>[signature.getParameterCount(hasReceiver)];
+        for (int i = 0; i < argumentTypes.length; i++) {
             int parameterIndex = i;
-            if (!target.isStatic()) {
+            if (hasReceiver) {
                 parameterIndex--;
             }
-            ValueNode argument = arguments.get(i);
-            if (folding || target.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex) != null) {
-                if (!(argument instanceof ConstantNode)) {
-                    return null;
+            if (target.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex) != null) {
+                ResolvedJavaType type = signature.getParameterType(parameterIndex, target.getDeclaringClass()).resolve(target.getDeclaringClass());
+                Class<?> cls;
+                if (type.isPrimitive()) {
+                    cls = type.getJavaKind().toJavaClass();
+                } else {
+                    cls = snippetReflection.asObject(Class.class, type.getJavaClass());
                 }
-                ConstantNode constantNode = (ConstantNode) argument;
-                Constant constant = constantNode.asConstant();
                 /*
-                 * For intrinsification (but not for folding) if we have a Class<?> object we want
-                 * the corresponding ResolvedJavaType.
+                 * If the node intrinsic method has a constant Class<?> argument, the node
+                 * constructor wants the corresponding ResolvedJavaType.
                  */
-                ResolvedJavaType type = folding ? null : constantReflection.asJavaType(constant);
-                Object arg;
-                if (type != null) {
-                    /* If we found such a type then it's our arg */
-                    arg = type;
-                    parameterTypes[i] = metaAccess.lookupJavaType(ResolvedJavaType.class);
+                if (cls.equals(Class.class)) {
+                    argumentTypes[i] = ResolvedJavaType.class;
                 } else {
-                    JavaConstant javaConstant = (JavaConstant) constant;
-                    if (folding) {
-                        /* For folding we want JavaConstants */
-                        arg = javaConstant;
-                    } else {
-                        /* For intrinsification we want want corresponding objects */
-                        if (parameterTypes[i].getJavaKind() == JavaKind.Boolean) {
-                            arg = Boolean.valueOf(javaConstant.asInt() != 0);
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Byte) {
-                            arg = Byte.valueOf((byte) javaConstant.asInt());
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Short) {
-                            arg = Short.valueOf((short) javaConstant.asInt());
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Char) {
-                            arg = Character.valueOf((char) javaConstant.asInt());
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Object) {
-                            arg = snippetReflection.asObject(parameterTypes[i], javaConstant);
-                        } else {
-                            arg = javaConstant.asBoxedPrimitive();
-                        }
-                    }
+                    argumentTypes[i] = cls;
                 }
+            } else {
+                argumentTypes[i] = ValueNode.class;
+            }
+        }
 
-                assert folding || !(arg instanceof JavaConstant);
-                reflectionCallArguments[i] = arg;
-            } else {
-                reflectionCallArguments[i] = argument;
-                parameterTypes[i] = metaAccess.lookupJavaType(ValueNode.class);
+        return argumentTypes;
+    }
+
+    /**
+     * Converts the arguments of an invoke node to object values suitable for use as the arguments
+     * to a reflective invocation of a ResolvedJavaMethod.
+     *
+     * @return the arguments for the reflective invocation or null if an argument of {@code invoke}
+     *         is not constant
+     */
+    private static JavaConstant[] prepareFoldingArguments(List<ValueNode> arguments) {
+        JavaConstant[] reflectionCallArguments = new JavaConstant[arguments.size()];
+        for (int i = 0; i < reflectionCallArguments.length; ++i) {
+            ValueNode argument = arguments.get(i);
+            if (!(argument instanceof ConstantNode)) {
+                return null;
             }
+
+            ConstantNode constantNode = (ConstantNode) argument;
+            reflectionCallArguments[i] = (JavaConstant) constantNode.asConstant();
         }
         return reflectionCallArguments;
     }
 
-    public ResolvedJavaType getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) {
-        ResolvedJavaType result;
+    public Class<? extends ValueNode> getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) {
+        Class<?> result;
         if (intrinsic.value() == NodeIntrinsic.class) {
-            result = target.getDeclaringClass();
+            ResolvedJavaType type = target.getDeclaringClass();
+            result = snippetReflection.asObject(Class.class, type.getJavaClass());
         } else {
-            result = metaAccess.lookupJavaType(intrinsic.value());
+            result = intrinsic.value();
         }
-        assert metaAccess.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + result.toJavaName(false) + " derived from @" + NodeIntrinsic.class.getSimpleName() +
-                        " annotation on " + target.format("%H.%n(%p)") + " is not a subclass of " + ValueNode.class;
-        return result;
+        assert ValueNode.class.isAssignableFrom(result) : "Node intrinsic class " + result + " derived from @" + NodeIntrinsic.class.getSimpleName() + " annotation on " + target.format("%H.%n(%p)") +
+                        " is not a subclass of " + ValueNode.class;
+        return result.asSubclass(ValueNode.class);
     }
 
-    protected ValueNode createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
-                    Object[] nodeConstructorArguments) {
-        ResolvedJavaMethod constructor = null;
-        Object[] arguments = null;
+    protected NodeIntrinsicFactory createIntrinsicFactory(Class<? extends ValueNode> nodeClass, Class<?>[] parameterTypes, List<ValueNode> arguments, Stamp invokeStamp, boolean setStampFromReturnType) {
+        NodeIntrinsicFactory ret = null;
 
-        for (ResolvedJavaMethod c : nodeClass.getDeclaredConstructors()) {
-            Object[] match = match(graph, invokeStamp, c, parameterTypes, nodeConstructorArguments);
+        for (Constructor<?> c : nodeClass.getDeclaredConstructors()) {
+            NodeIntrinsicFactory match = match(invokeStamp, setStampFromReturnType, c, parameterTypes, arguments);
 
             if (match != null) {
-                if (constructor == null) {
-                    constructor = c;
-                    arguments = match;
+                if (ret == null) {
+                    ret = match;
                     if (!Debug.isEnabled()) {
                         // Don't verify there's a unique match in non-debug mode
                         break;
                     }
                 } else {
-                    throw new JVMCIError("Found multiple constructors in %s compatible with signature %s: %s, %s", nodeClass.toJavaName(), sigString(parameterTypes), constructor, c);
+                    throw new JVMCIError("Found multiple constructors in %s compatible with signature %s", nodeClass.getName(), sigString(parameterTypes));
                 }
             }
         }
-        if (constructor == null) {
-            throw new JVMCIError("Could not find constructor in %s compatible with signature %s", nodeClass.toJavaName(), sigString(parameterTypes));
+
+        if (ret == null) {
+            throw new JVMCIError("Could not find constructor in %s compatible with signature %s", nodeClass.getName(), sigString(parameterTypes));
         }
 
-        try {
-            ValueNode intrinsicNode = (ValueNode) invokeConstructor(constructor, arguments);
-
-            if (setStampFromReturnType) {
-                intrinsicNode.setStamp(invokeStamp);
-            }
-            return intrinsicNode;
-        } catch (Exception e) {
-            throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e);
-        }
+        return ret;
     }
 
     protected Object invokeConstructor(ResolvedJavaMethod constructor, Object[] arguments) {
         return snippetReflection.invoke(constructor, null, arguments);
     }
 
-    private static String sigString(ResolvedJavaType[] types) {
+    private static String sigString(Class<?>[] types) {
         StringBuilder sb = new StringBuilder("(");
         for (int i = 0; i < types.length; i++) {
             if (i != 0) {
                 sb.append(", ");
             }
-            sb.append(types[i].toJavaName());
+            sb.append(types[i].getSimpleName());
         }
         return sb.append(")").toString();
     }
 
-    private static boolean checkNoMoreInjected(ResolvedJavaMethod c, int start) {
-        int count = c.getSignature().getParameterCount(false);
+    private static boolean checkNoMoreInjected(Constructor<?> c, int start) {
+        int count = c.getParameterCount();
         for (int i = start; i < count; i++) {
-            if (c.getParameterAnnotation(InjectedNodeParameter.class, i) != null) {
-                throw new JVMCIError("Injected parameter %d of type %s must precede all non-injected parameters of %s", i,
-                                c.getSignature().getParameterType(i, c.getDeclaringClass()).toJavaName(false), c.format("%H.%n(%p)"));
+            if (getParameterAnnotation(c, InjectedNodeParameter.class, i) != null) {
+                throw new JVMCIError("Injected parameter %d of type %s must precede all non-injected parameters of %s", i, c.getParameterTypes()[i], c.toString());
             }
         }
         return true;
     }
 
-    private Object[] match(StructuredGraph graph, Stamp invokeStamp, ResolvedJavaMethod c, ResolvedJavaType[] parameterTypes, Object[] nodeConstructorArguments) {
-        Object[] arguments = null;
-        Object[] injected = null;
+    private static <T extends Annotation> T getParameterAnnotation(Executable e, Class<T> annotationClass, int parameterIndex) {
+        if (parameterIndex >= 0) {
+            Annotation[][] parameterAnnotations = e.getParameterAnnotations();
+            for (Annotation a : parameterAnnotations[parameterIndex]) {
+                if (a.annotationType() == annotationClass) {
+                    return annotationClass.cast(a);
+                }
+            }
+        }
+        return null;
+    }
 
-        ResolvedJavaType[] signature = resolveJavaTypes(c.getSignature().toParameterTypes(null), c.getDeclaringClass());
+    private NodeIntrinsicFactory match(Stamp invokeStamp, boolean setStampFromReturnType, Constructor<?> c, Class<?>[] parameterTypes, List<ValueNode> argumentNodes) {
+        Class<?>[] signature = c.getParameterTypes();
+
+        int injectedCount = 0;
         for (int i = 0; i < signature.length; i++) {
-            if (c.getParameterAnnotation(InjectedNodeParameter.class, i) != null) {
-                injected = injected == null ? new Object[1] : Arrays.copyOf(injected, injected.length + 1);
-                Object injectedParameter = snippetReflection.getInjectedNodeIntrinsicParameter(signature[i]);
-                if (injectedParameter != null) {
-                    injected[injected.length - 1] = injectedParameter;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(MetaAccessProvider.class))) {
-                    injected[injected.length - 1] = metaAccess;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(StructuredGraph.class))) {
-                    injected[injected.length - 1] = graph;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(ForeignCallsProvider.class))) {
-                    injected[injected.length - 1] = foreignCalls;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(SnippetReflectionProvider.class))) {
-                    injected[injected.length - 1] = snippetReflection;
-                } else if (signature[i].isAssignableFrom(metaAccess.lookupJavaType(Stamp.class))) {
-                    injected[injected.length - 1] = invokeStamp;
-                } else if (signature[i].isAssignableFrom(metaAccess.lookupJavaType(StampProvider.class))) {
-                    injected[injected.length - 1] = stampProvider;
-                } else {
-                    throw new JVMCIError("Cannot handle injected argument of type %s in %s", signature[i].toJavaName(), c.format("%H.%n(%p)"));
-                }
+            if (getParameterAnnotation(c, InjectedNodeParameter.class, i) != null) {
+                injectedCount++;
             } else {
                 assert checkNoMoreInjected(c, i);
                 break;
             }
         }
-        if (injected != null) {
+
+        Object[] injected = null;
+        if (injectedCount > 0) {
+            injected = new Object[injectedCount];
+            for (int i = 0; i < injected.length; i++) {
+                assert getParameterAnnotation(c, InjectedNodeParameter.class, i) != null;
+                Object injectedParameter = snippetReflection.getInjectedNodeIntrinsicParameter(signature[i]);
+                if (injectedParameter != null) {
+                    injected[i] = injectedParameter;
+                } else if (signature[i].equals(MetaAccessProvider.class)) {
+                    injected[i] = metaAccess;
+                } else if (signature[i].equals(StructuredGraph.class)) {
+                    injected[i] = NodeIntrinsicFactory.GRAPH_MARKER;
+                } else if (signature[i].equals(ForeignCallsProvider.class)) {
+                    injected[i] = foreignCalls;
+                } else if (signature[i].equals(SnippetReflectionProvider.class)) {
+                    injected[i] = snippetReflection;
+                } else if (signature[i].isAssignableFrom(Stamp.class)) {
+                    injected[i] = invokeStamp;
+                } else if (signature[i].isAssignableFrom(StampProvider.class)) {
+                    injected[i] = stampProvider;
+                } else {
+                    throw new JVMCIError("Cannot handle injected argument of type %s in %s", signature[i].getName(), c.toString());
+                }
+            }
+
             // Chop injected arguments from signature
             signature = Arrays.copyOfRange(signature, injected.length, signature.length);
         }
 
         if (Arrays.equals(parameterTypes, signature)) {
             // Exact match
-            arguments = nodeConstructorArguments;
+            return new NodeIntrinsicFactory(invokeStamp, metaAccess.lookupJavaMethod(c), setStampFromReturnType, injected, parameterTypes, argumentNodes);
 
         } else if (signature.length > 0 && signature[signature.length - 1].isArray()) {
             // Last constructor parameter is an array, so check if we have a vararg match
@@ -401,35 +438,22 @@
                 }
             }
 
-            ResolvedJavaType componentType = signature[fixedArgs].getComponentType();
+            Class<?> componentType = signature[fixedArgs].getComponentType();
             assert componentType != null;
-            for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) {
+            for (int i = fixedArgs; i < argumentNodes.size(); i++) {
                 if (!parameterTypes[i].equals(componentType)) {
                     return null;
                 }
             }
-            arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1);
-            arguments[fixedArgs] = snippetReflection.newArray(componentType, nodeConstructorArguments.length - fixedArgs);
 
-            Object varargs = arguments[fixedArgs];
-            for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) {
-                if (componentType.isPrimitive()) {
-                    Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]);
-                } else {
-                    ((Object[]) varargs)[i - fixedArgs] = nodeConstructorArguments[i];
-                }
-            }
+            List<ValueNode> fixed = argumentNodes.subList(0, fixedArgs);
+            List<ValueNode> varargs = argumentNodes.subList(fixedArgs, argumentNodes.size());
+
+            return new NodeIntrinsicFactory(invokeStamp, metaAccess.lookupJavaMethod(c), setStampFromReturnType, injected, parameterTypes, fixed, componentType, varargs);
+
         } else {
             return null;
         }
-
-        if (injected != null) {
-            Object[] copy = new Object[injected.length + arguments.length];
-            System.arraycopy(injected, 0, copy, 0, injected.length);
-            System.arraycopy(arguments, 0, copy, injected.length, arguments.length);
-            arguments = copy;
-        }
-        return arguments;
     }
 
     private static String sourceLocation(Node n) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java	Tue Nov 24 19:31:56 2015 +0100
@@ -22,55 +22,21 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.replacements.NodeIntrinsificationPhase.COULD_NOT_FOLD;
-import static jdk.vm.ci.meta.MetaUtil.resolveJavaTypes;
-
-import java.util.Arrays;
-import java.util.List;
-
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
 
 import com.oracle.graal.api.replacements.Fold;
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.debug.MethodFilter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.nodeinfo.InputType;
-import com.oracle.graal.nodeinfo.StructuralInput;
-import com.oracle.graal.nodeinfo.StructuralInput.MarkerType;
-import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.extended.ForeignCallNode;
-import com.oracle.graal.nodes.extended.UnsafeCopyNode;
-import com.oracle.graal.nodes.extended.UnsafeLoadNode;
-import com.oracle.graal.nodes.extended.UnsafeStoreNode;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.nodes.graphbuilderconf.NodePlugin;
-import com.oracle.graal.word.WordTypes;
 
 /**
  * An {@link NodePlugin} that handles methods annotated by {@link Fold} and {@link NodeIntrinsic}.
  */
 public class NodeIntrinsificationPlugin implements NodePlugin {
-    protected final NodeIntrinsificationPhase nodeIntrinsification;
-    private final WordTypes wordTypes;
-    private final ResolvedJavaType structuralInputType;
-    private final boolean mustIntrinsify;
-
-    public NodeIntrinsificationPlugin(MetaAccessProvider metaAccess, NodeIntrinsificationPhase nodeIntrinsification, WordTypes wordTypes, boolean mustIntrinsify) {
-        this.nodeIntrinsification = nodeIntrinsification;
-        this.wordTypes = wordTypes;
-        this.mustIntrinsify = mustIntrinsify;
-        this.structuralInputType = metaAccess.lookupJavaType(StructuralInput.class);
-    }
 
     /**
      * Calls in replacements to methods matching one of these filters are elided. Only void methods
@@ -89,46 +55,7 @@
 
     @Override
     public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method);
-        if (intrinsic != null) {
-            Signature sig = method.getSignature();
-            JavaKind returnKind = sig.getReturnKind();
-            Stamp stamp = StampFactory.forKind(returnKind);
-            if (returnKind == JavaKind.Object) {
-                JavaType returnType = sig.getReturnType(method.getDeclaringClass());
-                if (returnType instanceof ResolvedJavaType) {
-                    ResolvedJavaType resolvedReturnType = (ResolvedJavaType) returnType;
-                    if (wordTypes.isWord(resolvedReturnType)) {
-                        stamp = wordTypes.getWordStamp(resolvedReturnType);
-                    } else {
-                        stamp = StampFactory.declared(resolvedReturnType);
-                    }
-                }
-            }
-
-            boolean result = processNodeIntrinsic(b, method, intrinsic, Arrays.asList(args), returnKind, stamp);
-            if (!result && mustIntrinsify) {
-                reportIntrinsificationFailure(b, method, args);
-            }
-            return result;
-
-        } else if (nodeIntrinsification.isFoldable(method)) {
-            ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
-            JavaConstant constant = nodeIntrinsification.tryFold(Arrays.asList(args), parameterTypes, method);
-            if (!COULD_NOT_FOLD.equals(constant)) {
-                if (constant != null) {
-                    // Replace the invoke with the result of the call
-                    b.push(method.getSignature().getReturnKind(), ConstantNode.forConstant(constant, b.getMetaAccess(), b.getGraph()));
-                } else {
-                    // This must be a void invoke
-                    assert method.getSignature().getReturnKind() == JavaKind.Void;
-                }
-                return true;
-            } else if (mustIntrinsify) {
-                reportIntrinsificationFailure(b, method, args);
-            }
-
-        } else if (MethodsElidedInSnippets != null) {
+        if (MethodsElidedInSnippets != null) {
             if (MethodFilter.matches(MethodsElidedInSnippets, method)) {
                 if (method.getSignature().getReturnKind() != JavaKind.Void) {
                     throw new JVMCIError("Cannot elide non-void method " + method.format("%H.%n(%p)"));
@@ -138,79 +65,4 @@
         }
         return false;
     }
-
-    private static boolean reportIntrinsificationFailure(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        StringBuilder msg = new StringBuilder();
-        msg.append("Call in ").append(b.getMethod().format("%H.%n(%p)"));
-        msg.append(" to ").append(method.format("%H.%n(%p)"));
-        msg.append(" cannot be intrinsified or folded, probably because an argument is not a constant. Arguments: ");
-        String sep = "";
-        for (ValueNode node : args) {
-            msg.append(sep).append(node.toString());
-            sep = ", ";
-        }
-        throw new JVMCIError(msg.toString());
-    }
-
-    private InputType getInputType(ResolvedJavaType type) {
-        if (type != null && structuralInputType.isAssignableFrom(type)) {
-            MarkerType markerType = type.getAnnotation(MarkerType.class);
-            if (markerType != null) {
-                return markerType.value();
-            } else {
-                throw JVMCIError.shouldNotReachHere(String.format("%s extends StructuralInput, but is not annotated with @MarkerType", type));
-            }
-        } else {
-            return InputType.Value;
-        }
-    }
-
-    private boolean processNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, JavaKind returnKind, Stamp stamp) {
-        ValueNode res = createNodeIntrinsic(b, method, intrinsic, args, stamp);
-        if (res == null) {
-            return false;
-        }
-        if (res instanceof UnsafeCopyNode) {
-            UnsafeCopyNode copy = (UnsafeCopyNode) res;
-            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) {
-            /*
-             * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the
-             * case that the foreign call can deoptimize. As with all deoptimization, we need a
-             * state in a non-intrinsic method.
-             */
-            GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
-            if (nonIntrinsicAncestor != null) {
-                ForeignCallNode foreign = (ForeignCallNode) res;
-                foreign.setBci(nonIntrinsicAncestor.bci());
-            }
-        }
-
-        boolean nonValueType = false;
-        if (returnKind == JavaKind.Object && stamp instanceof ObjectStamp) {
-            ResolvedJavaType type = ((ObjectStamp) stamp).type();
-            if (type != null && structuralInputType.isAssignableFrom(type)) {
-                assert res.isAllowedUsageType(getInputType(type));
-                nonValueType = true;
-            }
-        }
-
-        if (returnKind != JavaKind.Void) {
-            assert nonValueType || res.getStackKind() != JavaKind.Void;
-            res = b.addPush(returnKind, res);
-        } else {
-            assert res.getStackKind() == JavaKind.Void;
-            res = b.add(res);
-        }
-
-        return true;
-    }
-
-    private ValueNode createNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, Stamp stamp) {
-        ValueNode res = nodeIntrinsification.createIntrinsicNode(args, stamp, method, b.getGraph(), intrinsic);
-        assert res != null : String.format("Could not create node intrinsic for call to %s as one of the arguments expected to be constant isn't: arguments=%s", method.format("%H.%n(%p)"), args);
-        return res;
-    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Nov 24 19:31:56 2015 +0100
@@ -81,6 +81,7 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GeneratedInvocationPlugin;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
@@ -120,8 +121,12 @@
         return graphBuilderPlugins;
     }
 
+    protected boolean hasGeneratedInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Fold.class) != null;
+    }
+
     protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
-        return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null || method.getAnnotation(Fold.class) != null;
+        return method.getAnnotation(Word.Operation.class) != null;
     }
 
     private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
@@ -144,7 +149,8 @@
             return null;
         }
         if (b.parsingIntrinsic()) {
-            assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), NodeIntrinsificationPlugin.class.getName());
+            assert !hasGeneratedInvocationPluginAnnotation(method) : format("%s should have been handled by a %s", method.format("%H.%n(%p)"), GeneratedInvocationPlugin.class.getSimpleName());
+            assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), WordOperationPlugin.class.getSimpleName());
 
             assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java	Tue Nov 24 19:31:56 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -127,7 +127,7 @@
     static class SnippetCounterSnippets implements Snippets {
 
         @Fold
-        private static int countOffset() {
+        static int countOffset() {
             try {
                 return (int) UNSAFE.objectFieldOffset(SnippetCounter.class.getDeclaredField("value"));
             } catch (Exception e) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Nov 24 15:21:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Nov 24 19:31:56 2015 +0100
@@ -766,6 +766,12 @@
                 }
             } while (exploded);
 
+            for (NodeIntrinsicFactory factory : snippetCopy.getNodes().filter(NodeIntrinsicFactory.class)) {
+                ValueNode intrinsic = factory.intrinsify(snippetCopy, providers.getConstantReflection(), snippetReflection);
+                assert intrinsic != null;
+                snippetCopy.replaceFixed(factory, intrinsic);
+            }
+
             GuardsStage guardsStage = args.cacheKey.guardsStage;
             // Perform lowering on the snippet
             if (!guardsStage.allowsFloatingGuards()) {
--- a/mx.graal/suite.py	Tue Nov 24 15:21:14 2015 +0100
+++ b/mx.graal/suite.py	Tue Nov 24 19:31:56 2015 +0100
@@ -518,6 +518,7 @@
       "javaCompliance" : "1.8",
       "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
       ],
       "workingSets" : "Graal,Replacements,AMD64",
     },
@@ -541,7 +542,10 @@
         "com.oracle.graal.compiler.test",
         "com.oracle.graal.replacements",
       ],
-      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER"
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Replacements,Test",
@@ -1113,6 +1117,7 @@
       "dependencies" : ["com.oracle.graal.replacements.verifier"],
       "distDependencies" : [
         "GRAAL_API",
+        "jvmci:JVMCI_SERVICE_PROCESSOR",
       ],
     },