changeset 23162:59bb4f5ec80e

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 13 Dec 2015 11:27:58 +0100
parents dfae34f1fe9b (current diff) c01c5942b880 (diff)
children 3cbe2cc6c9ef
files 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/NodeIntrinsicPluginGenerator.java
diffstat 41 files changed, 1019 insertions(+), 820 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Dec 13 11:27:58 2015 +0100
@@ -80,6 +80,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp;
+import com.oracle.graal.lir.amd64.AMD64PauseOp;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGenerator;
 import com.oracle.graal.phases.util.Providers;
@@ -439,4 +440,9 @@
     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
         append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getLIRKind())));
     }
+
+    @Override
+    public void emitPause() {
+        append(new AMD64PauseOp());
+    }
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Sun Dec 13 11:27:58 2015 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.lir.LIRFrameState;
 import com.oracle.graal.lir.amd64.AMD64BreakpointOp;
 import com.oracle.graal.lir.amd64.AMD64Call;
-import com.oracle.graal.lir.amd64.AMD64PauseOp;
 import com.oracle.graal.lir.gen.LIRGeneratorTool;
 import com.oracle.graal.nodes.BreakpointNode;
 import com.oracle.graal.nodes.DeoptimizingNode;
@@ -41,7 +40,6 @@
 import com.oracle.graal.nodes.FixedWithNextNode;
 import com.oracle.graal.nodes.IfNode;
 import com.oracle.graal.nodes.IndirectCallTargetNode;
-import com.oracle.graal.nodes.PauseNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FixedBinaryNode;
@@ -116,11 +114,6 @@
     }
 
     @Override
-    public void visitPauseNode(PauseNode node) {
-        append(new AMD64PauseOp());
-    }
-
-    @Override
     public AMD64LIRGenerator getLIRGeneratorTool() {
         return (AMD64LIRGenerator) gen;
     }
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Sun Dec 13 11:27:58 2015 +0100
@@ -85,6 +85,7 @@
 import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
 import com.oracle.graal.lir.sparc.SPARCOP3Op;
+import com.oracle.graal.lir.sparc.SPARCPauseOp;
 import com.oracle.graal.phases.util.Providers;
 
 /**
@@ -449,4 +450,9 @@
         LIR lir = getResult().getLIR();
         loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase);
     }
+
+    @Override
+    public void emitPause() {
+        append(new SPARCPauseOp());
+    }
 }
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Sun Dec 13 11:27:58 2015 +0100
@@ -33,9 +33,7 @@
 import com.oracle.graal.lir.gen.LIRGeneratorTool;
 import com.oracle.graal.lir.sparc.SPARCBreakpointOp;
 import com.oracle.graal.lir.sparc.SPARCJumpOp;
-import com.oracle.graal.lir.sparc.SPARCPauseOp;
 import com.oracle.graal.nodes.BreakpointNode;
-import com.oracle.graal.nodes.PauseNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 
@@ -67,11 +65,6 @@
     }
 
     @Override
-    public void visitPauseNode(PauseNode node) {
-        append(new SPARCPauseOp());
-    }
-
-    @Override
     protected JumpOp newJumpOp(LabelRef ref) {
         return new SPARCJumpOp(ref);
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Sun Dec 13 11:27:58 2015 +0100
@@ -41,7 +41,6 @@
 import com.oracle.graal.hotspot.meta.HotSpotRegistersProvider;
 import com.oracle.graal.lir.LIRInstructionClass;
 import com.oracle.graal.lir.Opcode;
-import com.oracle.graal.lir.VirtualStackSlot;
 import com.oracle.graal.lir.asm.CompilationResultBuilder;
 
 @Opcode("BenchMarkCounter")
@@ -50,12 +49,12 @@
 
     @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot;
 
-    public AMD64HotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config, VirtualStackSlot backupSlot) {
+    public AMD64HotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue backupSlot) {
         super(TYPE, name, group, increment, registers, config);
         this.backupSlot = backupSlot;
     }
 
-    public AMD64HotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config, VirtualStackSlot backupSlot) {
+    public AMD64HotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue backupSlot) {
         super(TYPE, names, groups, increments, registers, config);
         this.backupSlot = backupSlot;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Sun Dec 13 11:27:58 2015 +0100
@@ -190,9 +190,9 @@
 
     private RescueSlotDummyOp rescueSlotOp;
 
-    private VirtualStackSlot getOrInitRescueSlot() {
+    private AllocatableValue getOrInitRescueSlot() {
         RescueSlotDummyOp op = getOrInitRescueSlotOp();
-        return (VirtualStackSlot) op.getSlot();
+        return op.getSlot();
     }
 
     private RescueSlotDummyOp getOrInitRescueSlotOp() {
@@ -615,7 +615,7 @@
         if (BenchmarkCounters.enabled) {
             return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot());
         }
-        return null;
+        throw JVMCIError.shouldNotReachHere("BenchmarkCounters are not enabled!");
     }
 
     @Override
@@ -623,7 +623,7 @@
         if (BenchmarkCounters.enabled) {
             return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot());
         }
-        return null;
+        throw JVMCIError.shouldNotReachHere("BenchmarkCounters are not enabled!");
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Sun Dec 13 11:27:58 2015 +0100
@@ -494,18 +494,16 @@
     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
         if (BenchmarkCounters.enabled) {
             return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
-        } else {
-            return null;
         }
+        throw JVMCIError.shouldNotReachHere("BenchmarkCounters are not enabled!");
     }
 
     @Override
     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
         if (BenchmarkCounters.enabled) {
             return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
-        } else {
-            return null;
         }
+        throw JVMCIError.shouldNotReachHere("BenchmarkCounters are not enabled!");
     }
 
     public AllocatableValue getSafepointAddressValue() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Sun Dec 13 11:27:58 2015 +0100
@@ -68,7 +68,6 @@
 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.NodeIntrinsicPluginFactory;
 import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.memory.address.AddressNode;
@@ -77,8 +76,8 @@
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.replacements.InlineDuringParsingPlugin;
 import com.oracle.graal.replacements.MethodHandlePlugin;
+import com.oracle.graal.replacements.NodeIntrinsificationPlugin;
 import com.oracle.graal.replacements.NodeIntrinsificationProvider;
-import com.oracle.graal.replacements.NodeIntrinsificationPlugin;
 import com.oracle.graal.replacements.ReplacementsImpl;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins;
 import com.oracle.graal.replacements.WordOperationPlugin;
@@ -131,7 +130,7 @@
                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, true);
 
                 for (NodeIntrinsicPluginFactory factory : Services.load(NodeIntrinsicPluginFactory.class)) {
-                    factory.registerPlugin(invocationPlugins, nodeIntrinsificationProvider);
+                    factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
                 }
 
             }
@@ -306,19 +305,13 @@
             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
             String arch = HotSpotVMConfig.config().getHostArchitectureName();
             String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
-            Class<?> c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.CipherBlockChaining", true);
-            if (c != null) {
-                Registration r = new Registration(plugins, c);
-                r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
-                r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
-                                int.class);
-            }
-            c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.AESCrypt", true);
-            if (c != null) {
-                Registration r = new Registration(plugins, c);
-                r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
-                r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
-            }
+            Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining");
+            r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
+            r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
+                            int.class);
+            r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt");
+            r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
+            r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Sun Dec 13 11:27:58 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import java.lang.reflect.Type;
+
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
@@ -51,7 +53,7 @@
     }
 
     @Override
-    public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+    public void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
         if (!config.usePopCountInstruction) {
             if (name.equals("bitCount")) {
                 assert declaringClass.equals(Integer.class) || declaringClass.equals(Long.class);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Sun Dec 13 11:27:58 2015 +0100
@@ -38,6 +38,7 @@
 import jdk.vm.ci.meta.Value;
 
 import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.debug.Indent;
 import com.oracle.graal.lir.LIRInsertionBuffer;
 import com.oracle.graal.lir.LIRInstruction;
@@ -46,6 +47,8 @@
  */
 public class MoveResolver {
 
+    private static final DebugMetric cycleBreakingSlotsAllocated = Debug.metric("LSRA[cycleBreakingSlotsAllocated]");
+
     private final LinearScan allocator;
 
     private int insertIdx;
@@ -369,6 +372,7 @@
         if (spillSlot == null) {
             spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
             fromInterval.setSpillSlot(spillSlot);
+            cycleBreakingSlotsAllocated.increment();
         }
         spillInterval(spillCandidate, fromInterval, spillSlot);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolver.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolver.java	Sun Dec 13 11:27:58 2015 +0100
@@ -48,6 +48,7 @@
 import jdk.vm.ci.meta.Value;
 
 import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.debug.Indent;
 import com.oracle.graal.lir.LIRInsertionBuffer;
 import com.oracle.graal.lir.LIRInstruction;
@@ -62,6 +63,8 @@
  */
 final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhase.MoveResolver {
 
+    private static final DebugMetric cycleBreakingSlotsAllocated = Debug.metric("TraceRA[cycleBreakingSlotsAllocated(global)]");
+
     private int insertIdx;
     private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
 
@@ -388,6 +391,7 @@
         Value from = mappingFrom.get(spillCandidate);
         try (Indent indent = Debug.logAndIndent("BreakCycle: %s", from)) {
             VirtualStackSlot spillSlot = frameMapBuilder.allocateSpillSlot(from.getLIRKind());
+            cycleBreakingSlotsAllocated.increment();
             if (Debug.isLogEnabled()) {
                 Debug.log("created new slot for spilling: %s", spillSlot);
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Sun Dec 13 11:27:58 2015 +0100
@@ -45,6 +45,7 @@
 import jdk.vm.ci.meta.Value;
 
 import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.debug.Indent;
 import com.oracle.graal.lir.LIRInsertionBuffer;
 import com.oracle.graal.lir.LIRInstruction;
@@ -56,6 +57,8 @@
  */
 final class TraceLocalMoveResolver {
 
+    private static final DebugMetric cycleBreakingSlotsAllocated = Debug.metric("TraceRA[cycleBreakingSlotsAllocated(local)]");
+
     private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
     private final TraceLinearScan allocator;
 
@@ -428,6 +431,7 @@
             if (spillSlot1 == null) {
                 spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval1.kind());
                 fromInterval1.setSpillSlot(spillSlot1);
+                cycleBreakingSlotsAllocated.increment();
             }
             spillInterval(spillCandidate, fromInterval1, spillSlot1);
             return;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Sun Dec 13 11:27:58 2015 +0100
@@ -257,4 +257,6 @@
     void emitBlackhole(Value operand);
 
     LIRKind getLIRKind(Stamp stamp);
+
+    void emitPause();
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Sun Dec 13 11:27:58 2015 +0100
@@ -70,7 +70,7 @@
         private final String name;
 
         MoveType(String dst, String src) {
-            this.name = String.format("%5s <- %s", dst, src);
+            this.name = src + '2' + dst;
         }
 
         @Override
@@ -156,7 +156,7 @@
                 }
             }
             String[] groups = new String[names.size()];
-            Arrays.fill(groups, "Move Operations");
+            Arrays.fill(groups, "MoveOperations");
             if (names.size() > 0) { // Don't pollute LIR when nothing has to be done
                 LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
                 assert inst != null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PauseNode.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PauseNode.java	Sun Dec 13 11:27:58 2015 +0100
@@ -40,7 +40,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.visitPauseNode(this);
+        gen.getLIRGeneratorTool().emitPause();
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugins.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugins.java	Sun Dec 13 11:27:58 2015 +0100
@@ -27,17 +27,19 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Launcher;
 
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodeIterable;
@@ -85,6 +87,40 @@
     }
 
     /**
+     * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
+     */
+    static class OptionalLazySymbol implements Type {
+        private static final Class<?> MASK_NULL = OptionalLazySymbol.class;
+        private final String name;
+        private Class<?> resolved;
+
+        public OptionalLazySymbol(String name) {
+            this.name = name;
+        }
+
+        public String getTypeName() {
+            return name;
+        }
+
+        /**
+         * Gets the resolved {@link Class} corresponding to this symbol or {@code null} if
+         * resolution fails.
+         */
+        public Class<?> resolve() {
+            if (resolved == null) {
+                Class<?> resolvedOrNull = resolveClass(name, true);
+                resolved = resolvedOrNull == null ? MASK_NULL : resolvedOrNull;
+            }
+            return resolved == MASK_NULL ? null : resolved;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    /**
      * Utility for
      * {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
      * registration} of invocation plugins.
@@ -92,7 +128,7 @@
     public static class Registration {
 
         private final InvocationPlugins plugins;
-        private final Class<?> declaringClass;
+        private final Type declaringType;
         private boolean allowOverwrite;
 
         /**
@@ -100,12 +136,12 @@
          * given class.
          *
          * @param plugins where to register the plugins
-         * @param declaringClass the class declaring the methods for which plugins will be
-         *            registered via this object
+         * @param declaringType the class declaring the methods for which plugins will be registered
+         *            via this object
          */
-        public Registration(InvocationPlugins plugins, Class<?> declaringClass) {
+        public Registration(InvocationPlugins plugins, Type declaringType) {
             this.plugins = plugins;
-            this.declaringClass = declaringClass;
+            this.declaringType = declaringType;
         }
 
         /**
@@ -118,11 +154,7 @@
          */
         public Registration(InvocationPlugins plugins, String declaringClassName) {
             this.plugins = plugins;
-            try {
-                this.declaringClass = Class.forName(declaringClassName);
-            } catch (ClassNotFoundException ex) {
-                throw JVMCIError.shouldNotReachHere(ex);
-            }
+            this.declaringType = new OptionalLazySymbol(declaringClassName);
         }
 
         /**
@@ -140,7 +172,7 @@
          * @param plugin the plugin to be registered
          */
         public void register0(String name, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name);
+            plugins.register(plugin, false, allowOverwrite, declaringType, name);
         }
 
         /**
@@ -149,8 +181,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg);
+        public void register1(String name, Type arg, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg);
         }
 
         /**
@@ -159,8 +191,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2);
+        public void register2(String name, Type arg1, Type arg2, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2);
         }
 
         /**
@@ -169,8 +201,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3);
+        public void register3(String name, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3);
         }
 
         /**
@@ -179,8 +211,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4);
+        public void register4(String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
         }
 
         /**
@@ -189,8 +221,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void register5(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, Class<?> arg5, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4, arg5);
+        public void register5(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5);
         }
 
         /**
@@ -200,7 +232,7 @@
          * @param plugin the plugin to be registered
          */
         public void registerOptional0(String name, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name);
+            plugins.register(plugin, true, allowOverwrite, declaringType, name);
         }
 
         /**
@@ -209,8 +241,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void registerOptional1(String name, Class<?> arg, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg);
+        public void registerOptional1(String name, Type arg, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg);
         }
 
         /**
@@ -219,8 +251,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void registerOptional2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2);
+        public void registerOptional2(String name, Type arg1, Type arg2, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg1, arg2);
         }
 
         /**
@@ -229,8 +261,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void registerOptional3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2, arg3);
+        public void registerOptional3(String name, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg1, arg2, arg3);
         }
 
         /**
@@ -239,8 +271,8 @@
          * @param name the name of the method
          * @param plugin the plugin to be registered
          */
-        public void registerOptional4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4);
+        public void registerOptional4(String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
         }
 
         /**
@@ -253,7 +285,7 @@
          *            is non-static. Upon returning, element 0 will have been rewritten to
          *            {@code declaringClass}
          */
-        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Class<?>... argumentTypes) {
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
             registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
         }
 
@@ -268,9 +300,9 @@
          *            is non-static. Upon returning, element 0 will have been rewritten to
          *            {@code declaringClass}
          */
-        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Class<?>... argumentTypes) {
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
             MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, substituteName, argumentTypes);
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, argumentTypes);
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
         }
     }
 
@@ -286,55 +318,73 @@
          */
         final boolean isOptional;
 
-        final Class<?> declaringClass;
         final String name;
-        final Class<?>[] argumentTypes;
+        final Type[] argumentTypes;
         final InvocationPlugin value;
 
-        MethodKey(InvocationPlugin data, boolean isStatic, boolean isOptional, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
-            assert isStatic || argumentTypes[0] == declaringClass;
+        /**
+         * Used to lazily initialize {@link #resolved}.
+         */
+        private final MetaAccessProvider metaAccess;
+
+        private volatile ResolvedJavaMethod resolved;
+
+        MethodKey(MetaAccessProvider metaAccess, InvocationPlugin data, boolean isStatic, boolean isOptional, String name, Type... argumentTypes) {
+            this.metaAccess = metaAccess;
             this.value = data;
             this.isStatic = isStatic;
             this.isOptional = isOptional;
-            this.declaringClass = declaringClass;
             this.name = name;
             this.argumentTypes = argumentTypes;
-            assert isOptional || resolveJava() != null;
         }
 
         @Override
         public boolean equals(Object obj) {
             if (obj instanceof MethodKey) {
                 MethodKey that = (MethodKey) obj;
-                boolean res = this.name.equals(that.name) && this.declaringClass.equals(that.declaringClass) && Arrays.equals(this.argumentTypes, that.argumentTypes);
+                boolean res = this.name.equals(that.name) && areEqual(this.argumentTypes, that.argumentTypes);
                 assert !res || this.isStatic == that.isStatic;
                 return res;
             }
             return false;
         }
 
+        private static boolean areEqual(Type[] args1, Type[] args2) {
+            if (args1.length == args2.length) {
+                for (int i = 0; i < args1.length; i++) {
+                    if (!args1[i].getTypeName().equals(args2[i].getTypeName())) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
         public int getDeclaredParameterCount() {
             return isStatic ? argumentTypes.length : argumentTypes.length - 1;
         }
 
         @Override
         public int hashCode() {
-            // Replay compilation mandates use of stable hash codes
-            return declaringClass.getName().hashCode() ^ name.hashCode();
+            return name.hashCode();
         }
 
-        private ResolvedJavaMethod resolve(MetaAccessProvider metaAccess) {
-            Executable method = resolveJava();
-            if (method == null) {
-                return null;
+        private ResolvedJavaMethod resolve(Class<?> declaringClass) {
+            if (resolved == null) {
+                Executable method = resolveJava(declaringClass);
+                if (method == null) {
+                    return null;
+                }
+                resolved = metaAccess.lookupJavaMethod(method);
             }
-            return metaAccess.lookupJavaMethod(method);
+            return resolved;
         }
 
-        private Executable resolveJava() {
+        private Executable resolveJava(Class<?> declaringClass) {
             try {
                 Executable res;
-                Class<?>[] parameterTypes = isStatic ? argumentTypes : Arrays.copyOfRange(argumentTypes, 1, argumentTypes.length);
+                Class<?>[] parameterTypes = resolveTypes(argumentTypes, isStatic ? 0 : 1, argumentTypes.length);
                 if (name.equals("<init>")) {
                     res = declaringClass.getDeclaredConstructor(parameterTypes);
                 } else {
@@ -352,12 +402,12 @@
 
         @Override
         public String toString() {
-            StringBuilder sb = new StringBuilder(declaringClass.getName()).append('.').append(name).append('(');
-            for (Class<?> p : argumentTypes) {
+            StringBuilder sb = new StringBuilder(name).append('(');
+            for (Type p : argumentTypes) {
                 if (sb.charAt(sb.length() - 1) != '(') {
                     sb.append(", ");
                 }
-                sb.append(p.getSimpleName());
+                sb.append(p.getTypeName());
             }
             return sb.append(')').toString();
         }
@@ -365,14 +415,11 @@
 
     private final MetaAccessProvider metaAccess;
 
-    /**
-     * Initial list of entries.
-     */
-    private final List<MethodKey> registrations = new ArrayList<>(INITIAL_CAPACITY);
+    private final Map<String, ClassPlugins> registrations = new HashMap<>();
 
     /**
-     * Deferred registrations as well as guard for initialization of {@link #entries}. The guard
-     * uses double-checked locking which is why this field is {@code volatile}.
+     * Deferred registrations as well as guard for initialization. The guard uses double-checked
+     * locking which is why this field is {@code volatile}.
      */
     private volatile List<Runnable> deferredRegistrations = new ArrayList<>();
 
@@ -381,16 +428,75 @@
      * {@link #get(ResolvedJavaMethod)} or {@link #closeRegistration()} is called on this object.
      */
     public void defer(Runnable deferrable) {
-        assert entries == null && deferredRegistrations != null : "registration is closed";
+        assert deferredRegistrations != null : "registration is closed";
         deferredRegistrations.add(deferrable);
     }
 
     /**
-     * Entry map that is initialized by {@link #initializeMap()}.
+     * Per-class invocation plugins.
      */
-    private Map<ResolvedJavaMethod, InvocationPlugin> entries;
+    protected static class ClassPlugins {
+        private final Type declaringType;
+
+        private final List<MethodKey> registrations = new ArrayList<>();
+
+        public ClassPlugins(Type declaringClass) {
+            this.declaringType = declaringClass;
+        }
+
+        /**
+         * Entry map that is initialized upon first call to {@link #get(ResolvedJavaMethod)}.
+         *
+         * Note: this must be volatile as threads may race to initialize it.
+         */
+        private volatile Map<ResolvedJavaMethod, InvocationPlugin> entries;
 
-    private static final int INITIAL_CAPACITY = 64;
+        void initializeMap() {
+            if (entries == null) {
+                if (registrations.isEmpty()) {
+                    entries = Collections.emptyMap();
+                } else {
+                    Class<?> declaringClass = resolveType(declaringType, true);
+                    if (declaringClass == null) {
+                        // An optional type that could not be resolved
+                        entries = Collections.emptyMap();
+                    } else {
+                        Map<ResolvedJavaMethod, InvocationPlugin> newEntries = new HashMap<>();
+                        for (MethodKey methodKey : registrations) {
+                            ResolvedJavaMethod m = methodKey.resolve(declaringClass);
+                            newEntries.put(m, methodKey.value);
+                            if (entries != null) {
+                                // Another thread finished initializing entries first
+                                return;
+                            }
+                        }
+                        entries = newEntries;
+                    }
+                }
+            }
+        }
+
+        public InvocationPlugin get(ResolvedJavaMethod method) {
+            if (entries == null) {
+                initializeMap();
+            }
+            return entries.get(method);
+        }
+
+        public void register(MethodKey methodKey, boolean allowOverwrite) {
+            assert entries == null : "registration is closed";
+            if (allowOverwrite) {
+                int index = registrations.indexOf(methodKey);
+                if (index >= 0) {
+                    registrations.set(index, methodKey);
+                    return;
+                }
+            } else {
+                assert !registrations.contains(methodKey) : "a value is already registered for " + declaringType + "." + methodKey;
+            }
+            registrations.add(methodKey);
+        }
+    }
 
     /**
      * Adds an entry to this map for a specified method.
@@ -404,27 +510,54 @@
      *            {@code declaringClass} iff the method is non-static.
      * @return an object representing the method
      */
-    MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+    MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
         assert isStatic || argumentTypes[0] == declaringClass;
-        MethodKey methodKey = new MethodKey(value, isStatic, isOptional, declaringClass, name, argumentTypes);
-        assert entries == null : "registration is closed";
-        assert allowOverwrite || !registrations.contains(methodKey) : "a value is already registered for " + methodKey;
-        registrations.add(methodKey);
+
+        String internalName = MetaUtil.toInternalName(declaringClass.getTypeName());
+        ClassPlugins classPlugins = registrations.get(internalName);
+        if (classPlugins == null) {
+            classPlugins = new ClassPlugins(declaringClass);
+            registrations.put(internalName, classPlugins);
+        }
+        assert isStatic || argumentTypes[0] == declaringClass;
+        MethodKey methodKey = new MethodKey(metaAccess, value, isStatic, isOptional, name, argumentTypes);
+        classPlugins.register(methodKey, allowOverwrite);
         return methodKey;
     }
 
     /**
      * Determines if a method denoted by a given {@link MethodKey} is in this map.
      */
-    boolean containsKey(MethodKey key) {
-        return registrations.contains(key);
+    boolean containsKey(Type declaringType, MethodKey key) {
+        String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
+        ClassPlugins classPlugins = registrations.get(internalName);
+        return classPlugins != null && classPlugins.registrations.contains(key);
     }
 
     InvocationPlugin get(ResolvedJavaMethod method) {
+        flushDeferrables();
+        String internalName = method.getDeclaringClass().getName();
+        ClassPlugins classPlugins = registrations.get(internalName);
+        if (classPlugins != null) {
+            return classPlugins.get(method);
+        }
+        return null;
+    }
+
+    private void flushDeferrables() {
         if (deferredRegistrations != null) {
-            initializeMap();
+            synchronized (this) {
+                if (deferredRegistrations != null) {
+                    for (Runnable deferrable : deferredRegistrations) {
+                        deferrable.run();
+                    }
+                    deferredRegistrations = null;
+                }
+            }
+            for (Map.Entry<String, ClassPlugins> e : registrations.entrySet()) {
+                e.getValue().initializeMap();
+            }
         }
-        return entries.get(method);
     }
 
     /**
@@ -432,32 +565,9 @@
      * lookup.
      */
     public void closeRegistration() {
-        if (deferredRegistrations != null) {
-            initializeMap();
-        }
-    }
-
-    void initializeMap() {
-        if (deferredRegistrations != null) {
-            synchronized (this) {
-                if (deferredRegistrations != null) {
-                    List<Runnable> localDeferredRegistrations = deferredRegistrations;
-                    for (Runnable deferrable : localDeferredRegistrations) {
-                        deferrable.run();
-                    }
-                    if (registrations.isEmpty()) {
-                        entries = Collections.emptyMap();
-                    } else {
-                        Map<ResolvedJavaMethod, InvocationPlugin> newEntries = new HashMap<>();
-                        for (MethodKey methodKey : registrations) {
-                            ResolvedJavaMethod m = methodKey.resolve(metaAccess);
-                            newEntries.put(m, methodKey.value);
-                        }
-                        entries = newEntries;
-                    }
-                    deferredRegistrations = null;
-                }
-            }
+        flushDeferrables();
+        for (Map.Entry<String, ClassPlugins> e : registrations.entrySet()) {
+            e.getValue().initializeMap();
         }
     }
 
@@ -492,13 +602,13 @@
         this(null, metaAccess);
     }
 
-    private void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+    private void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
         boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
         if (!isStatic) {
             argumentTypes[0] = declaringClass;
         }
-        MethodKey methodInfo = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);
-        assert Checker.check(this, methodInfo, plugin);
+        MethodKey methodKey = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);
+        assert Checker.check(this, declaringClass, methodKey, plugin);
     }
 
     /**
@@ -510,10 +620,14 @@
      *            non-static. Upon returning, element 0 will have been rewritten to
      *            {@code declaringClass}
      */
-    public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+    public void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
         register(plugin, false, false, declaringClass, name, argumentTypes);
     }
 
+    public void register(InvocationPlugin plugin, String declaringClass, String name, Type... argumentTypes) {
+        register(plugin, false, false, new OptionalLazySymbol(declaringClass), name, argumentTypes);
+    }
+
     /**
      * Registers an invocation plugin for a given, optional method. There must be no plugin
      * currently registered for {@code method}.
@@ -523,7 +637,7 @@
      *            non-static. Upon returning, element 0 will have been rewritten to
      *            {@code declaringClass}
      */
-    public void registerOptional(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+    public void registerOptional(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
         register(plugin, true, false, declaringClass, name, argumentTypes);
     }
 
@@ -553,7 +667,13 @@
 
     @Override
     public String toString() {
-        return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", ")) + " / parent: " + this.parent;
+        StringBuilder buf = new StringBuilder();
+        registrations.forEach((name, cp) -> buf.append(name).append('.').append(cp).append(", "));
+        String s = buf.toString();
+        if (buf.length() != 0) {
+            s = s.substring(buf.length() - ", ".length());
+        }
+        return s + " / parent: " + this.parent;
     }
 
     private static class Checker {
@@ -583,10 +703,10 @@
             SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
         }
 
-        public static boolean check(InvocationPlugins plugins, MethodKey method, InvocationPlugin plugin) {
+        public static boolean check(InvocationPlugins plugins, Type declaringType, MethodKey method, InvocationPlugin plugin) {
             InvocationPlugins p = plugins.parent;
             while (p != null) {
-                assert !p.containsKey(method) : "a plugin is already registered for " + method;
+                assert !p.containsKey(declaringType, method) : "a plugin is already registered for " + method;
                 p = p.parent;
             }
             if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
@@ -624,4 +744,64 @@
             parent.checkNewNodes(b, plugin, newNodes);
         }
     }
+
+    /**
+     * Resolves a name to a class.
+     *
+     * @param className the name of the class to resolve
+     * @param optional if true, resolution failure returns null
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?> resolveClass(String className, boolean optional) {
+        try {
+            // Need to use launcher class path to handle classes
+            // that are not on the boot class path
+            ClassLoader cl = Launcher.getLauncher().getClassLoader();
+            return Class.forName(className, false, cl);
+        } catch (ClassNotFoundException e) {
+            if (optional) {
+                return null;
+            }
+            throw new JVMCIError("Could not resolve type " + className);
+        }
+    }
+
+    /**
+     * Resolves a {@link Type} to a {@link Class}.
+     *
+     * @param type the type to resolve
+     * @param optional if true, resolution failure returns null
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?> resolveType(Type type, boolean optional) {
+        if (type instanceof Class) {
+            return (Class<?>) type;
+        }
+        if (optional && type instanceof OptionalLazySymbol) {
+            return ((OptionalLazySymbol) type).resolve();
+        }
+        return resolveClass(type.getTypeName(), optional);
+    }
+
+    private static final Class<?>[] NO_CLASSES = {};
+
+    /**
+     * Resolves an array of {@link Type}s to an array of {@link Class}es.
+     *
+     * @param types the types to resolve
+     * @param from the initial index of the range to be resolved, inclusive
+     * @param to the final index of the range to be resolved, exclusive
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?>[] resolveTypes(Type[] types, int from, int to) {
+        int length = to - from;
+        if (length <= 0) {
+            return NO_CLASSES;
+        }
+        Class<?>[] classes = new Class<?>[length];
+        for (int i = 0; i < length; i++) {
+            classes[i] = resolveType(types[i + from], false);
+        }
+        return classes;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Sun Dec 13 11:27:58 2015 +0100
@@ -22,15 +22,17 @@
  */
 package com.oracle.graal.nodes.graphbuilderconf;
 
+import static com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.resolveType;
+
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.stream.Collectors;
 
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import sun.misc.Launcher;
 
 import com.oracle.graal.nodes.ValueNode;
 
@@ -56,7 +58,7 @@
     /**
      * The parameter types of the substitute method.
      */
-    private final Class<?>[] parameters;
+    private final Type[] parameters;
 
     private final boolean originalIsStatic;
 
@@ -69,7 +71,7 @@
      *            static, then {@code parameters[0]} must be the {@link Class} value denoting
      *            {@link InvocationPlugin.Receiver}
      */
-    public MethodSubstitutionPlugin(Class<?> declaringClass, String name, Class<?>... parameters) {
+    public MethodSubstitutionPlugin(Class<?> declaringClass, String name, Type... parameters) {
         this.declaringClass = declaringClass;
         this.name = name;
         this.parameters = parameters;
@@ -83,7 +85,7 @@
      * @param name the name of the substitute method
      * @param parameters the parameter types of the substitute method
      */
-    public MethodSubstitutionPlugin(boolean originalIsStatic, Class<?> declaringClass, String name, Class<?>... parameters) {
+    public MethodSubstitutionPlugin(boolean originalIsStatic, Class<?> declaringClass, String name, Type... parameters) {
         this.declaringClass = declaringClass;
         this.name = name;
         this.parameters = parameters;
@@ -130,12 +132,12 @@
                 int start = 0;
                 if (!originalIsStatic) {
                     start = 1;
-                    if (!mparams[0].isAssignableFrom(parameters[0])) {
+                    if (!mparams[0].isAssignableFrom(resolveType(parameters[0], false))) {
                         return false;
                     }
                 }
                 for (int i = start; i < mparams.length; i++) {
-                    if (mparams[i] != parameters[i]) {
+                    if (mparams[i] != resolveType(parameters[i], false)) {
                         return false;
                     }
                 }
@@ -157,27 +159,6 @@
         throw new JVMCIError("No method found specified by %s", this);
     }
 
-    /**
-     * Resolves a name to a class.
-     *
-     * @param className the name of the class to resolve
-     * @param optional if true, resolution failure returns null
-     * @return the resolved class or null if resolution fails and {@code optional} is true
-     */
-    public static Class<?> resolveClass(String className, boolean optional) {
-        try {
-            // Need to use launcher class path to handle classes
-            // that are not on the boot class path
-            ClassLoader cl = Launcher.getLauncher().getClassLoader();
-            return Class.forName(className, false, cl);
-        } catch (ClassNotFoundException e) {
-            if (optional) {
-                return null;
-            }
-            throw new JVMCIError("Could not resolve type " + className);
-        }
-    }
-
     @Override
     public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
         ResolvedJavaMethod subst = getSubstitute(b.getMetaAccess());
@@ -201,6 +182,6 @@
     @Override
     public String toString() {
         return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name,
-                        Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect(Collectors.joining(", ")));
+                        Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", ")));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java	Sun Dec 13 11:27:58 2015 +0100
@@ -33,5 +33,5 @@
         Stamp getReturnStamp(Class<?> type);
     }
 
-    void registerPlugin(InvocationPlugins plugins, InjectionProvider injection);
+    void registerPlugins(InvocationPlugins plugins, InjectionProvider injection);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Sun Dec 13 11:27:58 2015 +0100
@@ -44,7 +44,6 @@
 import com.oracle.graal.nodes.IfNode;
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.LoopEndNode;
-import com.oracle.graal.nodes.PauseNode;
 import com.oracle.graal.nodes.SafepointNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
@@ -78,8 +77,6 @@
 
     void visitBreakpointNode(BreakpointNode i);
 
-    void visitPauseNode(PauseNode i);
-
     void visitFullInfopointNode(FullInfopointNode i);
 
     void recordSimpleInfopoint(InfopointReason reason, BytecodePosition position);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/FoldTest.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/FoldTest.java	Sun Dec 13 11:27:58 2015 +0100
@@ -95,8 +95,7 @@
         Plugins ret = super.getDefaultGraphBuilderPlugins();
         // manually register generated factories, jvmci service providers don't work from unit tests
         InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
-        new FoldFactory_FoldTest_FoldUtils_getNumber().registerPlugin(ret.getInvocationPlugins(), injection);
-        new FoldFactory_FoldTest_FoldUtils_multiply_255f288().registerPlugin(ret.getInvocationPlugins(), injection);
+        new PluginFactory_FoldTest().registerPlugins(ret.getInvocationPlugins(), injection);
         return ret;
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Sun Dec 13 11:27:58 2015 +0100
@@ -48,7 +48,7 @@
     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);
+        new PluginFactory_ReplacementsParseTest().registerPlugins(ret.getInvocationPlugins(), null);
         return ret;
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Sun Dec 13 11:27:58 2015 +0100
@@ -128,9 +128,7 @@
     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);
+        new PluginFactory_SubstitutionsTest().registerPlugins(ret.getInvocationPlugins(), null);
         return ret;
     }
 
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Sun Dec 13 11:27:58 2015 +0100
@@ -26,18 +26,9 @@
 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;
 
 /**
@@ -105,81 +96,6 @@
         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);
     }
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java	Sun Dec 13 11:27:58 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
@@ -43,7 +43,7 @@
         this.env = env;
     }
 
-    public abstract void verify(Element element, AnnotationMirror annotation);
+    public abstract void verify(Element element, AnnotationMirror annotation, PluginGenerator generator);
 
     public abstract Class<? extends Annotation> getAnnotationClass();
 
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java	Sun Dec 13 11:27:58 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
@@ -52,7 +52,7 @@
     }
 
     @Override
-    public void verify(Element element, AnnotationMirror classSubstitution) {
+    public void verify(Element element, AnnotationMirror classSubstitution, PluginGenerator generator) {
         if (!element.getKind().isClass()) {
             assert false : "Element is guaranteed to be a class.";
             return;
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/FoldPluginGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-/*
- * 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.TypeElement;
-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 argCount = 0;
-        Object receiver;
-        if (intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
-            receiver = intrinsicMethod.getEnclosingElement();
-        } else {
-            receiver = "arg0";
-            TypeElement type = (TypeElement) intrinsicMethod.getEnclosingElement();
-            constantArgument(out, deps, argCount, type.asType(), argCount);
-            argCount++;
-        }
-
-        int firstArg = argCount;
-        for (VariableElement param : params) {
-            constantArgument(out, deps, argCount, param.asType(), argCount);
-            argCount++;
-        }
-
-        if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
-            out.printf("            @SuppressWarnings(\"deprecation\")\n");
-        }
-        out.printf("            %s result = %s.%s(", intrinsicMethod.getReturnType(), receiver, intrinsicMethod.getSimpleName());
-        if (argCount > firstArg) {
-            out.printf("arg%d", firstArg);
-            for (int i = firstArg + 1; i < argCount; 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/FoldVerifier.java	Sun Dec 13 11:27:58 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 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.lang.annotation.Annotation;
+
+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.tools.Diagnostic.Kind;
+
+import com.oracle.graal.api.replacements.Fold;
+
+public final class FoldVerifier extends AbstractVerifier {
+
+    public FoldVerifier(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationClass() {
+        return Fold.class;
+    }
+
+    @Override
+    public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+        if (element.getKind() != ElementKind.METHOD) {
+            assert false : "Element is guaranteed to be a method.";
+            return;
+        }
+
+        ExecutableElement foldMethod = (ExecutableElement) element;
+        if (foldMethod.getModifiers().contains(Modifier.PRIVATE)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must not be private.", Fold.class.getSimpleName()), element, annotation);
+        } else {
+            generator.addPlugin(new GeneratedFoldPlugin(foldMethod));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/GeneratedFoldPlugin.java	Sun Dec 13 11:27:58 2015 +0100
@@ -0,0 +1,132 @@
+/*
+ * 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 java.util.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+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 GeneratedFoldPlugin extends GeneratedPlugin {
+
+    public GeneratedFoldPlugin(ExecutableElement intrinsicMethod) {
+        super(intrinsicMethod);
+    }
+
+    private static TypeMirror stringType(ProcessingEnvironment env) {
+        return env.getElementUtils().getTypeElement("java.lang.String").asType();
+    }
+
+    @Override
+    public void extraImports(Set<String> imports) {
+        imports.add("jdk.vm.ci.meta.JavaConstant");
+        imports.add("jdk.vm.ci.meta.JavaKind");
+        imports.add("com.oracle.graal.nodes.ConstantNode");
+    }
+
+    @Override
+    protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
+        InjectedDependencies deps = new InjectedDependencies();
+        List<? extends VariableElement> params = intrinsicMethod.getParameters();
+
+        int argCount = 0;
+        Object receiver;
+        if (intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            receiver = intrinsicMethod.getEnclosingElement();
+        } else {
+            receiver = "arg0";
+            TypeElement type = (TypeElement) intrinsicMethod.getEnclosingElement();
+            constantArgument(env, out, deps, argCount, type.asType(), argCount);
+            argCount++;
+        }
+
+        int firstArg = argCount;
+        for (VariableElement param : params) {
+            constantArgument(env, out, deps, argCount, param.asType(), argCount);
+            argCount++;
+        }
+
+        if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
+            out.printf("            @SuppressWarnings(\"deprecation\")\n");
+        }
+        out.printf("            %s result = %s.%s(", intrinsicMethod.getReturnType(), receiver, intrinsicMethod.getSimpleName());
+        if (argCount > firstArg) {
+            out.printf("arg%d", firstArg);
+            for (int i = firstArg + 1; i < argCount; 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(env))) {
+                    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/GeneratedNodeIntrinsicPlugin.java	Sun Dec 13 11:27:58 2015 +0100
@@ -0,0 +1,175 @@
+/*
+ * 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 java.util.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+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 abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin {
+
+    private final TypeMirror[] signature;
+
+    public GeneratedNodeIntrinsicPlugin(ExecutableElement intrinsicMethod, TypeMirror[] signature) {
+        super(intrinsicMethod);
+        this.signature = signature;
+    }
+
+    private static TypeMirror valueNodeType(ProcessingEnvironment env) {
+        return env.getElementUtils().getTypeElement("com.oracle.graal.nodes.ValueNode").asType();
+    }
+
+    protected abstract List<? extends VariableElement> getParameters();
+
+    protected abstract void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount);
+
+    @Override
+    protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
+        InjectedDependencies deps = new InjectedDependencies();
+
+        List<? extends VariableElement> params = getParameters();
+
+        int idx = 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(env, out, deps, idx, signature[i], i);
+            } else {
+                if (signature[i].equals(valueNodeType(env))) {
+                    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);
+                }
+            }
+        }
+
+        factoryCall(env, out, deps, idx);
+
+        return deps;
+    }
+
+    public static class ConstructorPlugin extends GeneratedNodeIntrinsicPlugin {
+
+        private final ExecutableElement constructor;
+
+        public ConstructorPlugin(ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+            super(intrinsicMethod, signature);
+            this.constructor = constructor;
+        }
+
+        @Override
+        public void extraImports(Set<String> imports) {
+            if (getReturnKind(intrinsicMethod) != JavaKind.Void) {
+                imports.add("jdk.vm.ci.meta.JavaKind");
+            }
+        }
+
+        @Override
+        protected List<? extends VariableElement> getParameters() {
+            return constructor.getParameters();
+        }
+
+        @Override
+        protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
+            out.printf("            %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
+            if (argCount > 0) {
+                out.printf("arg0");
+                for (int i = 1; i < argCount; 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");
+        }
+    }
+
+    public static class CustomFactoryPlugin extends GeneratedNodeIntrinsicPlugin {
+
+        private final ExecutableElement customFactory;
+
+        public CustomFactoryPlugin(ExecutableElement intrinsicMethod, ExecutableElement customFactory, TypeMirror[] signature) {
+            super(intrinsicMethod, signature);
+            this.customFactory = customFactory;
+        }
+
+        @Override
+        public void extraImports(Set<String> imports) {
+        }
+
+        @Override
+        protected List<? extends VariableElement> getParameters() {
+            List<? extends VariableElement> ret = customFactory.getParameters();
+            // remove initial GraphBuilderContext parameter
+            return ret.subList(1, ret.size());
+        }
+
+        @Override
+        protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
+            out.printf("            return %s.%s(b", customFactory.getEnclosingElement(), customFactory.getSimpleName());
+            for (int i = 0; i < argCount; 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);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/GeneratedPlugin.java	Sun Dec 13 11:27:58 2015 +0100
@@ -0,0 +1,197 @@
+/*
+ * 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.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+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 jdk.vm.ci.meta.JavaKind;
+
+import com.oracle.graal.replacements.verifier.InjectedDependencies.Dependency;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+public abstract class GeneratedPlugin {
+
+    protected final ExecutableElement intrinsicMethod;
+    private boolean needInjectionProvider;
+
+    public GeneratedPlugin(ExecutableElement intrinsicMethod) {
+        this.intrinsicMethod = intrinsicMethod;
+        this.needInjectionProvider = false;
+    }
+
+    public void generate(ProcessingEnvironment env, PrintWriter out, int idx) {
+        out.printf("    // class:  %s\n", intrinsicMethod.getEnclosingElement());
+        out.printf("    // method: %s\n", intrinsicMethod);
+        out.printf("    private static final class Plugin%d extends GeneratedInvocationPlugin {\n", idx);
+        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(env, out);
+        out.printf("        }\n");
+
+        createPrivateMembers(out, deps, idx);
+
+        out.printf("    }\n");
+    }
+
+    public void register(PrintWriter out, int idx) {
+        out.printf("        plugins.register(new Plugin%d(", idx);
+        if (needInjectionProvider) {
+            out.printf("injection");
+        }
+        out.printf("), %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
+        if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            out.printf(", InvocationPlugin.Receiver.class");
+        }
+        for (VariableElement arg : intrinsicMethod.getParameters()) {
+            out.printf(", %s.class", getErasedType(arg.asType()));
+        }
+        out.printf(");\n");
+    }
+
+    public abstract void extraImports(Set<String> imports);
+
+    protected abstract InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out);
+
+    private static TypeMirror resolvedJavaTypeType(ProcessingEnvironment env) {
+        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
+    }
+
+    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();
+        }
+    }
+
+    private void createPrivateMembers(PrintWriter out, InjectedDependencies deps, int idx) {
+        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%d(InjectionProvider injection) {\n", idx);
+            for (Dependency dep : deps) {
+                out.printf("            this.%s = %s;\n", dep.name, dep.inject(intrinsicMethod));
+            }
+            out.printf("        }\n");
+
+            needInjectionProvider = true;
+        }
+    }
+
+    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 static void constantArgument(ProcessingEnvironment env, 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(env))) {
+            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/InjectedDependencies.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/InjectedDependencies.java	Sun Dec 13 11:27:58 2015 +0100
@@ -67,7 +67,7 @@
 
         @Override
         public String inject(ExecutableElement inject) {
-            return String.format("injection.getReturnStamp(%s.class)", NodeIntrinsicPluginGenerator.getErasedType(inject.getReturnType()));
+            return String.format("injection.getReturnStamp(%s.class)", GeneratedPlugin.getErasedType(inject.getReturnType()));
         }
     }
 
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java	Sun Dec 13 11:27:58 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
@@ -67,7 +67,7 @@
 
     @SuppressWarnings("unused")
     @Override
-    public void verify(Element element, AnnotationMirror annotation) {
+    public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
         if (element.getKind() != ElementKind.METHOD) {
             assert false : "Element is guaranteed to be a method.";
             return;
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicPluginGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * 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	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Sun Dec 13 11:27:58 2015 +0100
@@ -77,11 +77,8 @@
         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
@@ -90,7 +87,7 @@
     }
 
     @Override
-    public void verify(Element element, AnnotationMirror annotation) {
+    public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
         if (element.getKind() != ElementKind.METHOD) {
             assert false : "Element is guaranteed to be a method.";
             return;
@@ -124,7 +121,7 @@
         TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
         ExecutableElement custom = findCustomIntrinsifyMethod(nodeClass, constructorSignature);
         if (custom != null) {
-            factoryGen.createPluginFactory(intrinsicMethod, custom, constructorSignature);
+            generator.addPlugin(new GeneratedNodeIntrinsicPlugin.CustomFactoryPlugin(intrinsicMethod, custom, constructorSignature));
         } else {
             if (isNodeType(nodeClass)) {
                 if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
@@ -137,7 +134,7 @@
 
                     ExecutableElement constructor = findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
                     if (constructor != null) {
-                        factoryGen.createPluginFactory(intrinsicMethod, constructor, constructorSignature);
+                        generator.addPlugin(new GeneratedNodeIntrinsicPlugin.ConstructorPlugin(intrinsicMethod, constructor, constructorSignature));
                     }
                 }
             } else {
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java	Sun Dec 13 11:27:58 2015 +0100
@@ -24,38 +24,42 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 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.Modifier;
 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 class PluginGenerator {
 
-public abstract class PluginGenerator {
+    private final Map<Element, List<GeneratedPlugin>> plugins;
 
-    protected final ProcessingEnvironment env;
-
-    public PluginGenerator(ProcessingEnvironment env) {
-        this.env = env;
+    public PluginGenerator() {
+        this.plugins = new HashMap<>();
     }
 
-    private TypeMirror resolvedJavaTypeType() {
-        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
+    public void addPlugin(GeneratedPlugin plugin) {
+        Element topLevel = getTopLevelClass(plugin.intrinsicMethod);
+        List<GeneratedPlugin> list = plugins.get(topLevel);
+        if (list == null) {
+            list = new ArrayList<>();
+            plugins.put(topLevel, list);
+        }
+        list.add(plugin);
+    }
+
+    public void generateAll(ProcessingEnvironment env) {
+        for (Entry<Element, List<GeneratedPlugin>> entry : plugins.entrySet()) {
+            createPluginFactory(env, entry.getKey(), entry.getValue());
+        }
     }
 
     private static Element getTopLevelClass(Element element) {
@@ -68,84 +72,30 @@
         return prev;
     }
 
-    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();
-        Element topLevelClass = getTopLevelClass(declaringClass);
+    private static void createPluginFactory(ProcessingEnvironment env, Element topLevelClass, List<GeneratedPlugin> plugins) {
         PackageElement pkg = (PackageElement) topLevelClass.getEnclosingElement();
 
-        String genClassName = mkFactoryClassName(intrinsicMethod);
+        String genClassName = "PluginFactory_" + topLevelClass.getSimpleName();
 
         try {
-            JavaFileObject factory = env.getFiler().createSourceFile(pkg.getQualifiedName() + "." + genClassName, topLevelClass, declaringClass, intrinsicMethod);
+            JavaFileObject factory = env.getFiler().createSourceFile(pkg.getQualifiedName() + "." + genClassName, topLevelClass);
             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);
+                createImports(out, plugins);
                 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");
+                int idx = 0;
+                for (GeneratedPlugin plugin : plugins) {
+                    out.printf("\n");
+                    plugin.generate(env, out, idx++);
+                }
                 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);
+                createPluginFactoryMethod(out, plugins);
                 out.printf("}\n");
             }
         } catch (IOException e) {
@@ -153,9 +103,7 @@
         }
     }
 
-    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) {
+    protected static void createImports(PrintWriter out, List<GeneratedPlugin> plugins) {
         out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
         out.printf("import jdk.vm.ci.service.ServiceProvider;\n");
         out.printf("\n");
@@ -165,103 +113,25 @@
         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()) {
+        HashSet<String> extra = new HashSet<>();
+        for (GeneratedPlugin plugin : plugins) {
+            plugin.extraImports(extra);
+        }
+        if (!extra.isEmpty()) {
             out.printf("\n");
-            for (Dependency dep : deps) {
-                out.printf("        private final %s %s;\n", dep.type, dep.name);
+            for (String i : extra) {
+                out.printf("import %s;\n", i);
             }
-
-            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());
-        if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
-            out.printf(", InvocationPlugin.Receiver.class");
+    private static void createPluginFactoryMethod(PrintWriter out, List<GeneratedPlugin> plugins) {
+        out.printf("    public void registerPlugins(InvocationPlugins plugins, InjectionProvider injection) {\n");
+        int idx = 0;
+        for (GeneratedPlugin plugin : plugins) {
+            plugin.register(out, idx++);
         }
-        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	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Sun Dec 13 11:27:58 2015 +0100
@@ -49,6 +49,7 @@
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         if (!roundEnv.processingOver()) {
+            PluginGenerator generator = new PluginGenerator();
             for (AbstractVerifier verifier : getVerifiers()) {
                 Class<? extends Annotation> annotationClass = verifier.getAnnotationClass();
                 for (Element e : roundEnv.getElementsAnnotatedWith(annotationClass)) {
@@ -57,9 +58,11 @@
                         assert false : "Annotation mirror always expected.";
                         continue;
                     }
-                    verifier.verify(e, annotationMirror);
+                    verifier.verify(e, annotationMirror, generator);
                 }
             }
+
+            generator.generateAll(processingEnv);
         }
         return false;
     }
@@ -84,7 +87,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());
+            verifiers.add(new FoldVerifier(this.processingEnv));
         }
         return verifiers;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sun Dec 13 11:27:58 2015 +0100
@@ -149,8 +149,12 @@
             return null;
         }
         if (b.parsingIntrinsic()) {
-            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());
+            if (hasGeneratedInvocationPluginAnnotation(method)) {
+                throw new JVMCIError("%s should have been handled by a %s", method.format("%H.%n(%p)"), GeneratedInvocationPlugin.class.getSimpleName());
+            }
+            if (hasGenericInvocationPluginAnnotation(method)) {
+                throw new JVMCIError("%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/StandardGraphBuilderPlugins.java	Sun Dec 13 11:27:37 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Sun Dec 13 11:27:58 2015 +0100
@@ -32,6 +32,17 @@
 import java.lang.reflect.Field;
 import java.util.Arrays;
 
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.LocationIdentity;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import sun.misc.Unsafe;
+
 import com.oracle.graal.api.directives.GraalDirectives;
 import com.oracle.graal.compiler.common.calc.Condition;
 import com.oracle.graal.compiler.common.calc.UnsignedMath;
@@ -74,9 +85,8 @@
 import com.oracle.graal.nodes.extended.UnsafeStoreNode;
 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.MethodSubstitutionPlugin;
-import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
 import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.java.ClassIsAssignableFromNode;
 import com.oracle.graal.nodes.java.CompareAndSwapNode;
@@ -101,31 +111,11 @@
 import com.oracle.graal.replacements.nodes.arithmetic.IntegerMulExactNode;
 import com.oracle.graal.replacements.nodes.arithmetic.IntegerSubExactNode;
 
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.DeoptimizationAction;
-import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.LocationIdentity;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionValue;
-import sun.misc.Unsafe;
-
 /**
  * Provides non-runtime specific {@link InvocationPlugin}s.
  */
 public class StandardGraphBuilderPlugins {
 
-    // @formatter:off
-    static class Options {
-        @Option(help = "Enable use of intrinsics for the JMH Blackhole class")
-        public static final OptionValue<Boolean> UseBlackholeSubstitution = new OptionValue<>(true);
-    }
-    // @formatter:on
-
     public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins, boolean allowDeoptimization) {
         registerObjectPlugins(plugins);
         registerClassPlugins(plugins);
@@ -146,9 +136,7 @@
         registerEdgesPlugins(metaAccess, plugins);
         registerGraalDirectivesPlugins(plugins);
         registerBoxingPlugins(plugins);
-        if (Options.UseBlackholeSubstitution.getValue()) {
-            registerJMHBlackholePlugins(plugins);
-        }
+        registerJMHBlackholePlugins(plugins);
         registerJFRThrowablePlugins(plugins);
     }
 
@@ -778,32 +766,24 @@
         };
         String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
         for (String name : names) {
-            Class<?> blackholeClass;
-            blackholeClass = MethodSubstitutionPlugin.resolveClass(name, true);
-            if (blackholeClass != null) {
-                Registration r = new Registration(plugins, blackholeClass);
-                for (JavaKind kind : JavaKind.values()) {
-                    if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
-                        Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
-                        r.register2("consume", Receiver.class, javaClass, blackholePlugin);
-                    }
+            Registration r = new Registration(plugins, name);
+            for (JavaKind kind : JavaKind.values()) {
+                if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
+                    Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+                    r.register2("consume", Receiver.class, javaClass, blackholePlugin);
                 }
-                r.register2("consume", Receiver.class, Object[].class, blackholePlugin);
             }
+            r.register2("consume", Receiver.class, Object[].class, blackholePlugin);
         }
     }
 
     private static void registerJFRThrowablePlugins(InvocationPlugins plugins) {
-        String name = "oracle.jrockit.jfr.jdkevents.ThrowableTracer";
-        Class<?> tracerClass = MethodSubstitutionPlugin.resolveClass(name, true);
-        if (tracerClass != null) {
-            Registration r = new Registration(plugins, tracerClass);
-            r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) {
-                    b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), throwable, message));
-                    return true;
-                }
-            });
-        }
+        Registration r = new Registration(plugins, "oracle.jrockit.jfr.jdkevents.ThrowableTracer");
+        r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) {
+                b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), throwable, message));
+                return true;
+            }
+        });
     }
 }
--- a/mx.graal/mx_graal_8.py	Sun Dec 13 11:27:37 2015 +0100
+++ b/mx.graal/mx_graal_8.py	Sun Dec 13 11:27:58 2015 +0100
@@ -282,6 +282,11 @@
         with Task('DaCapo_pmd:BatchMode:product', tasks) as t:
             if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-Xbatch', 'pmd'])
 
+    # ensure benchmark counters still work
+    with VM('jvmci', 'product'):
+        with Task('DaCapo_pmd:BenchmarkCounters:product', tasks) as t:
+            if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-G:+LIRProfileMoves', '-G:+GenericDynamicCounters', '-XX:JVMCICounterSize=10', 'pmd'])
+
     # ensure -Xcomp still works
     with VM('jvmci', 'product'):
         with Task('XCompMode:product', tasks) as t:
--- a/mx.graal/mx_graal_9.py	Sun Dec 13 11:27:37 2015 +0100
+++ b/mx.graal/mx_graal_9.py	Sun Dec 13 11:27:58 2015 +0100
@@ -271,6 +271,11 @@
         with Task('DaCapo_pmd:BatchMode', tasks) as t:
             if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-Xbatch', 'pmd'])
 
+    # ensure benchmark counters still work
+    with JVMCIMode('jit'):
+        with Task('DaCapo_pmd:BenchmarkCounters:product', tasks) as t:
+            if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-G:+LIRProfileMoves', '-G:+GenericDynamicCounters', '-XX:JVMCICounterSize=10', 'pmd'])
+
     # ensure -Xcomp still works
     with JVMCIMode('jit'):
         with Task('XCompMode:product', tasks) as t:
--- a/mx.graal/suite.py	Sun Dec 13 11:27:37 2015 +0100
+++ b/mx.graal/suite.py	Sun Dec 13 11:27:58 2015 +0100
@@ -47,7 +47,7 @@
             },
             {
                "name" : "truffle",
-               "version" : "bc1e026ef5b1ab8a1f68a3e78437e48f2d91fd91",
+               "version" : "66f79c26f8977bb7eb246b70d90b39385f846be7",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/truffle", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},