changeset 19143:f10ca512eb40

Merge with cd49455040c1d57d8ab74473b3786ecc4f663060
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Wed, 04 Feb 2015 16:38:09 -0800
parents 64e6c7b83515 (current diff) cd49455040c1 (diff)
children b8b8f0fcb8c3
files graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/OpaqueNode.java
diffstat 51 files changed, 1050 insertions(+), 630 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -998,7 +998,7 @@
     }
 
     @Override
-    public Value emitBitCount(Value value) {
+    public Variable emitBitCount(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value)));
@@ -1009,14 +1009,14 @@
     }
 
     @Override
-    public Value emitBitScanForward(Value value) {
+    public Variable emitBitScanForward(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value)));
         return result;
     }
 
     @Override
-    public Value emitBitScanReverse(Value value) {
+    public Variable emitBitScanReverse(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value)));
@@ -1098,14 +1098,14 @@
     }
 
     @Override
-    public Value emitByteSwap(Value input) {
+    public Variable emitByteSwap(Value input) {
         Variable result = newVariable(LIRKind.derive(input));
         append(new AMD64ByteSwapOp(result, input));
         return result;
     }
 
     @Override
-    public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
+    public Variable emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
         Variable result = newVariable(LIRKind.value(Kind.Int));
         append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
         return result;
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -189,7 +189,7 @@
     }
 
     @Override
-    public Value emitAddress(StackSlotValue address) {
+    public Variable emitAddress(StackSlotValue address) {
         Variable result = newVariable(LIRKind.value(target().wordKind));
         append(new StackLoadAddressOp(result, address));
         return result;
@@ -422,7 +422,7 @@
     }
 
     @Override
-    public Value emitBitCount(Value operand) {
+    public Variable emitBitCount(Value operand) {
         Variable result = newVariable(LIRKind.derive(operand).changeType(Kind.Int));
         if (operand.getKind().getStackKind() == Kind.Int) {
             append(new SPARCBitManipulationOp(IPOPCNT, result, asAllocatable(operand), this));
@@ -433,14 +433,14 @@
     }
 
     @Override
-    public Value emitBitScanForward(Value operand) {
+    public Variable emitBitScanForward(Value operand) {
         Variable result = newVariable(LIRKind.derive(operand).changeType(Kind.Int));
         append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), this));
         return result;
     }
 
     @Override
-    public Value emitBitScanReverse(Value operand) {
+    public Variable emitBitScanReverse(Value operand) {
         Variable result = newVariable(LIRKind.derive(operand).changeType(Kind.Int));
         if (operand.getKind().getStackKind() == Kind.Int) {
             append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), this));
@@ -493,14 +493,14 @@
     }
 
     @Override
-    public Value emitByteSwap(Value input) {
+    public Variable emitByteSwap(Value input) {
         Variable result = newVariable(LIRKind.derive(input));
         append(new SPARCByteSwapOp(this, result, input));
         return result;
     }
 
     @Override
-    public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
+    public Variable emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
         Variable result = newVariable(LIRKind.value(Kind.Int));
         append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length)));
         return result;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Wed Feb 04 16:38:09 2015 -0800
@@ -67,7 +67,7 @@
         StructuredGraph graph = new StructuredGraph(javaMethod);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, conf, OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Feb 04 16:38:09 2015 -0800
@@ -839,8 +839,9 @@
     protected PhaseSuite<HighTierContext> getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) {
         PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
+        GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) iterator.previous();
         iterator.remove();
-        iterator.add(new GraphBuilderPhase(gbConf));
+        iterator.add(new GraphBuilderPhase(gbConf, graphBuilderPhase.getGraphBuilderPlugins()));
         return suite;
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Wed Feb 04 16:38:09 2015 -0800
@@ -152,7 +152,8 @@
         graph = new StructuredGraph(method);
         try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
             Assumptions assumptions = new Assumptions(false);
-            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
+                            OptimisticOptimizations.ALL).apply(graph);
             context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Wed Feb 04 16:38:09 2015 -0800
@@ -238,7 +238,7 @@
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
                     Assumptions assumptions = new Assumptions(false);
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, null, graphBuilderConfig, optimisticOpts);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     Debug.handle(ex);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Feb 04 16:38:09 2015 -0800
@@ -166,7 +166,7 @@
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
-        startGVNNumber = clazz.hashCode();
+        startGVNNumber = clazz.getName().hashCode();
 
         NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class);
         assert info != null : "Missing NodeInfo annotation on " + clazz;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -527,7 +527,7 @@
         }
     }
 
-    public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
         LIRKind kind = newValue.getLIRKind();
         assert kind.equals(expectedValue.getLIRKind());
         Kind memKind = (Kind) kind.getPlatformKind();
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -220,7 +220,7 @@
         append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
     }
 
-    public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
         Variable newValueTemp = newVariable(newValue.getLIRKind());
         emitMove(newValueTemp, newValue);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -49,7 +49,7 @@
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlotValue slot = hsGen.getLockSlot(lockDepth);
         // The register allocator cannot handle stack -> register moves so we use an LEA here
-        Value result = gen.getLIRGeneratorTool().emitMove(gen.getLIRGeneratorTool().emitAddress(slot));
+        Value result = gen.getLIRGeneratorTool().emitAddress(slot);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Wed Feb 04 16:38:09 2015 -0800
@@ -25,6 +25,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,17 +38,9 @@
 @ServiceProvider(GraphBuilderPluginsProvider.class)
 public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
     public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, ObjectPlugin.class);
-    }
-
-    /**
-     * HotSpot specific plugins for {@link Object}.
-     */
-    enum ObjectPlugin implements GraphBuilderPlugin {
-        getClass() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                assert args.length == 1;
-                ValueNode rcvr = args[0];
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("getClass", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
                 GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr));
                 StampProvider stampProvider = builder.getStampProvider();
                 LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi));
@@ -53,10 +48,6 @@
                 builder.push(Kind.Object, mirror);
                 return true;
             }
-        };
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name());
-        }
+        });
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Wed Feb 04 16:38:09 2015 -0800
@@ -36,6 +36,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -687,7 +688,10 @@
         Kind kind = field.getKind();
         T receiver = frameState.apop();
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+            GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ValueNode) receiver, (ResolvedJavaField) field)) {
+                appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+            }
         } else {
             handleUnresolvedLoadField(field, receiver);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java	Wed Feb 04 16:38:09 2015 -0800
@@ -0,0 +1,62 @@
+/*
+ * 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.java;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Default implementation of {@link GraphBuilderPlugins} that uses a map.
+ */
+public class DefaultGraphBuilderPlugins implements GraphBuilderPlugins {
+
+    private final Map<ResolvedJavaMethod, InvocationPlugin> plugins = new HashMap<>();
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
+        assert InvocationPluginChecker.check(method, plugin);
+        GraphBuilderPlugin oldValue = plugins.put(method, plugin);
+        // System.out.println("registered: " + plugin);
+        assert oldValue == null;
+    }
+
+    /**
+     * Gets the plugin for a given method.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        return plugins.get(method);
+    }
+
+    @Override
+    public String toString() {
+        return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java	Wed Feb 04 16:34:07 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +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.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
- */
-@ServiceProvider(GraphBuilderPluginsProvider.class)
-public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
-    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, ObjectPlugin.class);
-        plugins.register(metaAccess, BoxingPlugin.class);
-    }
-
-    /**
-     * Plugins for {@link Object}.
-     */
-    enum ObjectPlugin implements GraphBuilderPlugin {
-        init() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode object = args[0];
-                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
-                    builder.append(new RegisterFinalizerNode(object));
-                }
-                return true;
-            }
-
-            public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-                return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, "<init>");
-            }
-        };
-
-        @Override
-        public String toString() {
-            return Object.class.getName() + "." + name() + "()";
-        }
-    }
-
-    /**
-     * Plugins for the standard primitive box classes (e.g., {@link Integer} and friends).
-     */
-    enum BoxingPlugin implements GraphBuilderPlugin {
-        valueOf$Boolean(Kind.Boolean),
-        booleanValue$Boolean(Kind.Boolean),
-        valueOf$Byte(Kind.Byte),
-        byteValue$Byte(Kind.Byte),
-        valueOf$Short(Kind.Short),
-        shortValue$Short(Kind.Short),
-        valueOf$Char(Kind.Char),
-        charValue$Char(Kind.Char),
-        valueOf$Int(Kind.Int),
-        intValue$Int(Kind.Int),
-        valueOf$Long(Kind.Long),
-        longValue$Long(Kind.Long),
-        valueOf$Float(Kind.Float),
-        floatValue$Float(Kind.Float),
-        valueOf$Double(Kind.Double),
-        doubleValue$Double(Kind.Double);
-
-        BoxingPlugin(Kind kind) {
-            assert name().startsWith("valueOf$") || name().startsWith(kind.getJavaName() + "Value$");
-            this.kind = kind;
-            this.box = name().charAt(0) == 'v';
-        }
-
-        private final Kind kind;
-        private final boolean box;
-
-        public final boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-            if (box) {
-                ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-                builder.push(Kind.Object, builder.append(new BoxNode(args[0], resultType, kind)));
-            } else {
-                builder.push(kind, builder.append(new UnboxNode(args[0], kind)));
-            }
-            return true;
-        }
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            Class<?>[] parameterTypes = box ? new Class<?>[]{kind.toJavaClass()} : new Class<?>[0];
-            return GraphBuilderPlugin.resolveTarget(metaAccess, kind.toBoxedJavaClass(), name(), parameterTypes);
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraalDirectivePlugins.java	Wed Feb 04 16:38:09 2015 -0800
@@ -0,0 +1,106 @@
+/*
+ * 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.java;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class GraalDirectivePlugins {
+
+    private static ResolvedJavaMethod lookup(MetaAccessProvider metaAccess, String name, Class<?>... parameterTypes) {
+        return Registration.resolve(metaAccess, GraalDirectives.class, name, parameterTypes);
+    }
+
+    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        plugins.register(lookup(metaAccess, "deoptimize"), new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        plugins.register(lookup(metaAccess, "deoptimizeAndInvalidate"), new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        plugins.register(lookup(metaAccess, "inCompiledCode"), new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Int, builder.append(ConstantNode.forInt(1)));
+                return true;
+            }
+        });
+
+        plugins.register(lookup(metaAccess, "controlFlowAnchor"), new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new ControlFlowAnchorNode());
+                return true;
+            }
+        });
+
+        plugins.register(lookup(metaAccess, "injectBranchProbability", double.class, boolean.class), new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
+                builder.push(Kind.Int, builder.append(new BranchProbabilityNode(probability, condition)));
+                return true;
+            }
+        });
+
+        InvocationPlugin blackholePlugin = new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.append(new BlackholeNode(value));
+                return true;
+            }
+        };
+
+        for (Kind kind : Kind.values()) {
+            Class<?> cls = null;
+            switch (kind) {
+                case Object:
+                    cls = Object.class;
+                    break;
+                case Void:
+                case Illegal:
+                    continue;
+                default:
+                    cls = kind.toJavaClass();
+            }
+
+            plugins.register(lookup(metaAccess, "blackhole", cls), blackholePlugin);
+
+            final Kind stackKind = kind.getStackKind();
+            plugins.register(lookup(metaAccess, "opaque", cls), new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                    builder.push(stackKind, builder.append(new OpaqueNode(value)));
+                    return true;
+                }
+            });
+        }
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Feb 04 16:38:09 2015 -0800
@@ -37,6 +37,8 @@
     private final DebugInfoMode debugInfoMode;
     private final boolean doLivenessAnalysis;
     private final boolean inlineTrivial;
+    private GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin;
+    private GraphBuilderPlugins.ParameterPlugin parameterPlugin;
 
     public static enum DebugInfoMode {
         SafePointsOnly,
@@ -72,6 +74,12 @@
         this.inlineTrivial = inlineTrivial;
     }
 
+    public GraphBuilderConfiguration copy() {
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
+        result.loadFieldPlugin = loadFieldPlugin;
+        return result;
+    }
+
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
     }
@@ -93,6 +101,14 @@
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newInlineTrivial);
     }
 
+    public GraphBuilderPlugins.LoadFieldPlugin getLoadFieldPlugin() {
+        return loadFieldPlugin;
+    }
+
+    public void setLoadFieldPlugin(GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin) {
+        this.loadFieldPlugin = loadFieldPlugin;
+    }
+
     public ResolvedJavaType[] getSkippedExceptionTypes() {
         return skippedExceptionTypes;
     }
@@ -145,4 +161,12 @@
     public boolean shouldInlineTrivial() {
         return inlineTrivial;
     }
+
+    public GraphBuilderPlugins.ParameterPlugin getParameterPlugin() {
+        return parameterPlugin;
+    }
+
+    public void setParameterPlugin(GraphBuilderPlugins.ParameterPlugin parameterPlugin) {
+        this.parameterPlugin = parameterPlugin;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Feb 04 16:38:09 2015 -0800
@@ -42,6 +42,7 @@
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
@@ -62,13 +63,18 @@
     private final GraphBuilderPlugins graphBuilderPlugins;
 
     public GraphBuilderPhase(GraphBuilderConfiguration config) {
+        this(config, new DefaultGraphBuilderPlugins());
+    }
+
+    public GraphBuilderPhase(GraphBuilderConfiguration config, GraphBuilderPlugins graphBuilderPlugins) {
         this.graphBuilderConfig = config;
-        this.graphBuilderPlugins = new GraphBuilderPlugins();
+        this.graphBuilderPlugins = graphBuilderPlugins;
     }
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), graphBuilderConfig, graphBuilderPlugins, context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), context.getConstantReflection(), graphBuilderConfig, graphBuilderPlugins,
+                        context.getOptimisticOptimizations()).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
@@ -92,6 +98,7 @@
         private final OptimisticOptimizations optimisticOpts;
         private final StampProvider stampProvider;
         private final Assumptions assumptions;
+        private final ConstantReflectionProvider constantReflectionProvider;
 
         /**
          * Gets the graph being processed by this builder.
@@ -100,19 +107,21 @@
             return currentGraph;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins,
-                        OptimisticOptimizations optimisticOpts) {
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
             this.assumptions = assumptions;
             this.graphBuilderPlugins = graphBuilderPlugins;
+            this.constantReflectionProvider = constantReflectionProvider;
             assert metaAccess != null;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
-            this(metaAccess, stampProvider, assumptions, graphBuilderConfig, null, optimisticOpts);
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+            this(metaAccess, stampProvider, assumptions, constantReflectionProvider, graphBuilderConfig, null, optimisticOpts);
         }
 
         @Override
@@ -123,7 +132,7 @@
             assert method.getCode() != null : "method must contain bytecodes: " + method;
             this.currentGraph = graph;
             HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, null);
-            frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving());
+            frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving(), this.graphBuilderConfig.getParameterPlugin());
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
                 BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI);
@@ -557,7 +566,7 @@
 
             @Override
             protected ValueNode genObjectEquals(ValueNode x, ValueNode y) {
-                return new ObjectEqualsNode(x, y);
+                return ObjectEqualsNode.create(x, y, constantReflectionProvider);
             }
 
             @Override
@@ -773,11 +782,10 @@
                 if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect()) {
 
                     if (graphBuilderPlugins != null) {
-                        GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod);
+                        InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod);
                         if (plugin != null) {
                             int beforeStackSize = frameState.stackSize;
-                            if (plugin.handleInvocation(this, args)) {
-                                // System.out.println("used plugin: " + plugin);
+                            if (plugin.apply(this, args)) {
                                 assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize;
                                 return;
                             }
@@ -998,7 +1006,6 @@
             }
 
             public <T extends FloatingNode> T append(T v) {
-                assert !(v instanceof ConstantNode);
                 T added = currentGraph.unique(v);
                 return added;
             }
@@ -1482,11 +1489,24 @@
                 }
                 condition = genUnique(condition);
 
-                ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
-                ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
+                if (condition instanceof LogicConstantNode) {
+                    LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
+                    boolean value = constantLogicNode.getValue();
+                    if (negate) {
+                        value = !value;
+                    }
+                    BciBlock nextBlock = falseBlock;
+                    if (value) {
+                        nextBlock = trueBlock;
+                    }
+                    appendGoto(createTarget(nextBlock, frameState));
+                } else {
+                    ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
+                    ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
-                ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability);
-                append(ifNode);
+                    ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability);
+                    append(ifNode);
+                }
             }
 
             public StampProvider getStampProvider() {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Wed Feb 04 16:38:09 2015 -0800
@@ -22,43 +22,14 @@
  */
 package com.oracle.graal.java;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-
 /**
- * Extensions for handling certain bytecode instructions while building a
- * {@linkplain StructuredGraph graph} from a bytecode stream.
+ * Marker interface for graph builder plugins.
+ *
+ * Concrete plugins implement one of the sub-interfaces of this interface.
+ *
+ * @see GraphBuilderPluginsProvider
+ * @see GraphBuilderPlugins
+ * @see GraphBuilderPlugins.Registration
  */
 public interface GraphBuilderPlugin {
-
-    /**
-     * Processes an invocation parsed in a bytecode stream and add nodes to a graph being
-     * constructed that implement the semantics of the invocation.
-     *
-     * @param builder object being used to build a graph
-     * @param args the arguments to the invocation
-     */
-    boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args);
-
-    /**
-     * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} .
-     */
-    ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess);
-
-    /**
-     * Looks up a {@link ResolvedJavaMethod}.
-     *
-     * @param methodNameBase the name of the method is the prefix of this value up to the first '$'
-     *            character
-     */
-    static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class<?> declaringClass, String methodNameBase, Class<?>... parameterTypes) {
-        int index = methodNameBase.indexOf('$');
-        String methodName = index == -1 ? methodNameBase : methodNameBase.substring(0, index);
-        try {
-            return metaAccess.lookupJavaMethod(methodName.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes));
-        } catch (NoSuchMethodException | SecurityException e) {
-            throw new GraalInternalError(e);
-        }
-    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Wed Feb 04 16:38:09 2015 -0800
@@ -22,45 +22,225 @@
  */
 package com.oracle.graal.java;
 
+import static java.lang.String.*;
+
+import java.lang.reflect.*;
 import java.util.*;
-import java.util.stream.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 
 /**
- * A repository of {@link GraphBuilderPlugin}s.
+ * Interface for managing a set of graph builder {@link GraphBuilderPlugin}s.
  */
-public class GraphBuilderPlugins {
+public interface GraphBuilderPlugins {
 
-    private final Map<ResolvedJavaMethod, GraphBuilderPlugin> map = new HashMap<>();
+    public interface LoadFieldPlugin extends GraphBuilderPlugin {
+        boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field);
+    }
+
+    public interface ParameterPlugin extends GraphBuilderPlugin {
+        FloatingNode interceptParameter(int index);
+    }
 
     /**
-     * Registers all the constants of an enum that implements {@link GraphBuilderPlugin}.
+     * Plugin for handling a method invocation.
      */
-    public <T extends Enum<T> & GraphBuilderPlugin> void register(MetaAccessProvider metaAccess, Class<T> enumClass) {
-        assert Enum.class.isAssignableFrom(enumClass);
-        Object[] enumConstants = enumClass.getEnumConstants();
-        for (Object o : enumConstants) {
-            GraphBuilderPlugin gbp = (GraphBuilderPlugin) o;
-            ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess);
-            GraphBuilderPlugin oldValue = map.put(target, gbp);
-            // System.out.println("registered: " + gbp);
-            assert oldValue == null;
+    public interface InvocationPlugin extends GraphBuilderPlugin {
+        /**
+         * Tries to handle an invocation to a method with no arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder) {
+            throw invalidHandler(builder);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with one argument.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg) {
+            throw invalidHandler(builder, arg);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with two arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
+            throw invalidHandler(builder, arg1, arg2);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with three arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+            throw invalidHandler(builder, arg1, arg2, arg3);
+        }
+
+        default boolean apply(GraphBuilderContext builder, ValueNode[] args) {
+            if (args.length == 0) {
+                return apply(builder);
+            } else if (args.length == 1) {
+                return apply(builder, args[0]);
+            } else if (args.length == 2) {
+                return apply(builder, args[0], args[1]);
+            } else if (args.length == 3) {
+                return apply(builder, args[0], args[1], args[2]);
+            } else {
+                throw invalidHandler(builder, args);
+            }
+        }
+
+        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) {
+            return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length);
         }
     }
 
     /**
-     * Gets the plugin for a given method registered in the object.
+     * Utility for {@linkplain GraphBuilderPlugins#register(ResolvedJavaMethod, InvocationPlugin)
+     * registration} of plugins.
+     */
+    public static class Registration {
+
+        /**
+         * Sentinel class for use with {@link Registration#register1},
+         * {@link Registration#register2} or {@link Registration#register3} to denote the receiver
+         * argument for a non-static method.
+         */
+        public static final class Receiver {
+            private Receiver() {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        private final GraphBuilderPlugins plugins;
+        private final MetaAccessProvider metaAccess;
+        private final Class<?> declaringClass;
+
+        /**
+         * Creates an object for registering plugins for methods declared by a given class.
+         *
+         * @param plugins where to register the plugins
+         * @param metaAccess used to resolve classes and methods
+         * @param declaringClass the class declaring the methods for which plugins will be
+         *            registered via this object
+         */
+        public Registration(GraphBuilderPlugins plugins, MetaAccessProvider metaAccess, Class<?> declaringClass) {
+            this.plugins = plugins;
+            this.metaAccess = metaAccess;
+            this.declaringClass = declaringClass;
+        }
+
+        /**
+         * Registers a plugin for a method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register0(String name, InvocationPlugin plugin) {
+            plugins.register(resolve(metaAccess, declaringClass, name), plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments.
+         *
+         * @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) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments.
+         *
+         * @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) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Resolves a method given a declaring class, name and parameter types.
+         */
+        public static ResolvedJavaMethod resolve(MetaAccessProvider metaAccess, Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+            try {
+                return metaAccess.lookupJavaMethod(name.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(name, parameterTypes));
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+    }
+
+    public static class InvocationPluginChecker {
+        static final Class<?>[] APPLY0 = {GraphBuilderContext.class};
+        static final Class<?>[] APPLY1 = {GraphBuilderContext.class, ValueNode.class};
+        static final Class<?>[] APPLY2 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class};
+        static final Class<?>[] APPLY3 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class, ValueNode.class};
+        static final Class<?>[][] SIGS = {APPLY0, APPLY1, APPLY2, APPLY3};
+
+        public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) {
+            int arguments = method.getSignature().getParameterCount(!method.isStatic());
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)"));
+            Method expected = null;
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    assert Arrays.equals(SIGS[arguments], parameterTypes) : format("graph builder plugin for %s has wrong signature%nexpected: (%s)%n  actual: (%s)", method.format("%H.%n(%p)"),
+                                    sigString(SIGS[arguments]), sigString(m.getParameterTypes()));
+                    expected = m;
+                }
+            }
+            assert expected != null : format("graph builder plugin %s must define exactly one \"apply\" method, none found", plugin);
+            return true;
+        }
+
+        protected static String sigString(Class<?>... sig) {
+            StringBuilder sb = new StringBuilder();
+            for (Class<?> t : sig) {
+                if (sb.length() != 0) {
+                    sb.append(", ");
+                }
+                sb.append(t.getSimpleName());
+            }
+            return sb.toString();
+        }
+
+    }
+
+    /**
+     * Registers an {@link InvocationPlugin} for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    void register(ResolvedJavaMethod method, InvocationPlugin plugin);
+
+    /**
+     * Gets the {@link InvocationPlugin} for a given method.
      *
      * @param method the method to lookup
      * @return the plugin associated with {@code method} or {@code null} if none exists
      */
-    public GraphBuilderPlugin getPlugin(ResolvedJavaMethod method) {
-        return map.get(method);
-    }
-
-    @Override
-    public String toString() {
-        return map.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
-    }
+    InvocationPlugin lookupInvocation(ResolvedJavaMethod method);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Wed Feb 04 16:38:09 2015 -0800
@@ -30,9 +30,7 @@
  */
 public interface GraphBuilderPluginsProvider extends Service {
     /**
-     * Registers the plugins provided by this object with a plugins registry.
-     *
-     * @param plugins registry of plugins
+     * Registers the plugins provided by this object.
      */
     void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Wed Feb 04 16:38:09 2015 -0800
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.java.GraphBuilderPlugins.ParameterPlugin;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -81,14 +82,20 @@
         }
     }
 
-    public final void initializeForMethodStart(boolean eagerResolve) {
+    public final void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
 
         int javaIndex = 0;
         int index = 0;
         if (!method.isStatic()) {
             // add the receiver
-            ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())));
-            storeLocal(javaIndex, receiver);
+            FloatingNode receiver = null;
+            if (parameterPlugin != null) {
+                receiver = parameterPlugin.interceptParameter(index);
+            }
+            if (receiver == null) {
+                receiver = new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()));
+            }
+            storeLocal(javaIndex, graph.unique(receiver));
             javaIndex = 1;
             index = 1;
         }
@@ -107,8 +114,14 @@
             } else {
                 stamp = StampFactory.forKind(kind);
             }
-            ParameterNode param = graph.unique(new ParameterNode(index, stamp));
-            storeLocal(javaIndex, param);
+            FloatingNode param = null;
+            if (parameterPlugin != null) {
+                param = parameterPlugin.interceptParameter(index);
+            }
+            if (param == null) {
+                param = new ParameterNode(index, stamp);
+            }
+            storeLocal(javaIndex, graph.unique(param));
             javaIndex += kind.getSlotCount();
             index++;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Wed Feb 04 16:38:09 2015 -0800
@@ -0,0 +1,99 @@
+/*
+ * 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.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
+ */
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class StandardGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("<init>", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode object) {
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
+                }
+                return true;
+            }
+        });
+
+        for (Kind kind : Kind.values()) {
+            if (kind.isPrimitive() && kind != Kind.Void) {
+                new BoxPlugin(kind).register(metaAccess, plugins);
+                new UnboxPlugin(kind).register(metaAccess, plugins);
+            }
+        }
+
+        GraalDirectivePlugins.registerPlugins(metaAccess, plugins);
+    }
+
+    static class BoxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        BoxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnboxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        UnboxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            builder.push(kind, builder.append(new UnboxNode(value, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
+            plugins.register(method, this);
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java	Wed Feb 04 16:38:09 2015 -0800
@@ -22,13 +22,19 @@
  */
 package com.oracle.graal.lir.framemap;
 
+import static com.oracle.graal.api.code.ValueUtil.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.stackslotalloc.*;
 
@@ -95,6 +101,9 @@
     public FrameMap buildFrameMap(LIRGenerationResult res, StackSlotAllocator allocator) {
         try (Scope s = Debug.scope("StackSlotAllocation")) {
             allocator.allocateStackSlots(this, res);
+            if (Debug.isEnabled()) {
+                verifyStackSlotAllocation(res);
+            }
         }
         for (CallingConvention cc : calls) {
             frameMap.callsMethod(cc);
@@ -103,6 +112,23 @@
         return frameMap;
     }
 
+    private static void verifyStackSlotAllocation(LIRGenerationResult res) {
+        LIR lir = res.getLIR();
+        InstructionValueConsumer verifySlots = (LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) -> {
+            assert !isVirtualStackSlot(value) : String.format("Instruction %s contains a virtual stack slot %s", op, value);
+        };
+        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+            lir.getLIRforBlock(block).forEach(op -> {
+                op.visitEachInput(verifySlots);
+                op.visitEachAlive(verifySlots);
+                op.visitEachState(verifySlots);
+
+                op.visitEachTemp(verifySlots);
+                op.visitEachOutput(verifySlots);
+            });
+        }
+    }
+
     public List<VirtualStackSlot> getStackSlots() {
         return stackSlots;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -119,6 +119,7 @@
 
     @Override
     public Variable emitMove(Value input) {
+        assert !(input instanceof Variable) : "Creating a copy of a variable via this method is not supported (and potentially a bug): " + input;
         Variable result = newVariable(input.getLIRKind());
         emitMove(result, input);
         return result;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Wed Feb 04 16:38:09 2015 -0800
@@ -54,13 +54,13 @@
 
     Value emitLoadConstant(LIRKind kind, Constant constant);
 
-    Value emitLoad(LIRKind kind, Value address, LIRFrameState state);
+    Variable emitLoad(LIRKind kind, Value address, LIRFrameState state);
 
     void emitStore(LIRKind kind, Value address, Value input, LIRFrameState state);
 
     void emitNullCheck(Value address, LIRFrameState state);
 
-    Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
+    Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
 
     /**
      * Emit an atomic read-and-add instruction.
@@ -112,7 +112,7 @@
 
     Value emitAddress(Value base, long displacement, Value index, int scale);
 
-    Value emitAddress(StackSlotValue slot);
+    Variable emitAddress(StackSlotValue slot);
 
     void emitMembar(int barriers);
 
@@ -179,15 +179,15 @@
 
     CallingConvention getCallingConvention();
 
-    Value emitBitCount(Value operand);
+    Variable emitBitCount(Value operand);
 
-    Value emitBitScanForward(Value operand);
+    Variable emitBitScanForward(Value operand);
 
-    Value emitBitScanReverse(Value operand);
+    Variable emitBitScanReverse(Value operand);
 
-    Value emitByteSwap(Value operand);
+    Variable emitByteSwap(Value operand);
 
-    Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length);
+    Variable emitArrayEquals(Kind kind, Value array1, Value array2, Value length);
 
     void emitBlackhole(Value operand);
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java	Wed Feb 04 16:38:09 2015 -0800
@@ -43,6 +43,7 @@
     private final LIR lir;
     private final int maxOpId;
     private final StackInterval[] stackSlotMap;
+    private final HashSet<LIRInstruction> usePos;
 
     /**
      * The number of allocated stack slots.
@@ -55,9 +56,15 @@
         this.maxOpId = maxOpId;
         liveInMap = new BlockMap<>(lir.getControlFlowGraph());
         liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+        this.usePos = new HashSet<>();
     }
 
-    void build() {
+    /**
+     * Builds the lifetime intervals for {@link VirtualStackSlot virtual stack slots}, sets up
+     * {@link #stackSlotMap} and returns a set of use positions, i.e. instructions that contain
+     * virtual stack slots.
+     */
+    Set<LIRInstruction> build() {
         Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
         for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
             worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
@@ -69,6 +76,7 @@
             AbstractBlock<?> block = worklist.poll();
             processBlock(block, worklist);
         }
+        return usePos;
     }
 
     /**
@@ -188,6 +196,7 @@
             if (isVirtualStackSlot(operand)) {
                 VirtualStackSlot vslot = asVirtualStackSlot(operand);
                 addUse(vslot, inst, flags);
+                usePos.add(inst);
                 Debug.log("set operand: %s", operand);
                 currentSet.set(vslot.getId());
             }
@@ -206,6 +215,7 @@
             if (isVirtualStackSlot(operand)) {
                 VirtualStackSlot vslot = asVirtualStackSlot(operand);
                 addDef(vslot, inst);
+                usePos.add(inst);
                 Debug.log("clear operand: %s", operand);
                 currentSet.clear(vslot.getId());
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -32,6 +32,7 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
@@ -58,8 +59,17 @@
         // @formatter:on
     }
 
+    private static final DebugTimer MainTimer = Debug.timer("LSStackSlotAllocator");
+    private static final DebugTimer NumInstTimer = Debug.timer("LSStackSlotAllocator[NumberInstruction]");
+    private static final DebugTimer BuildIntervalsTimer = Debug.timer("LSStackSlotAllocator[BuildIntervals]");
+    private static final DebugTimer VerifyIntervalsTimer = Debug.timer("LSStackSlotAllocator[VerifyIntervals]");
+    private static final DebugTimer AllocateSlotsTimer = Debug.timer("LSStackSlotAllocator[AllocateSlots]");
+    private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]");
+
     public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
-        new Allocator(res.getLIR(), builder).allocate();
+        try (TimerCloseable t = MainTimer.start()) {
+            new Allocator(res.getLIR(), builder).allocate();
+        }
     }
 
     private static final class Allocator {
@@ -82,33 +92,42 @@
             // insert by to
             this.active = new PriorityQueue<>((a, b) -> a.to() - b.to());
 
-            // step 1: number instructions
-            this.maxOpId = numberInstructions(lir, sortedBlocks);
+            try (TimerCloseable t = NumInstTimer.start()) {
+                // step 1: number instructions
+                this.maxOpId = numberInstructions(lir, sortedBlocks);
+            }
         }
 
         private void allocate() {
             Debug.dump(lir, "After StackSlot numbering");
 
             long currentFrameSize = Debug.isMeterEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0;
+            Set<LIRInstruction> usePos;
             // step 2: build intervals
-            try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals")) {
-                buildIntervals();
+            try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals"); TimerCloseable t = BuildIntervalsTimer.start()) {
+                usePos = buildIntervals();
             }
             // step 3: verify intervals
             if (Debug.isEnabled()) {
-                verifyIntervals();
+                try (TimerCloseable t = VerifyIntervalsTimer.start()) {
+                    verifyIntervals();
+                }
             }
             if (Debug.isDumpEnabled()) {
                 dumpIntervals("Before stack slot allocation");
             }
             // step 4: allocate stack slots
-            allocateStackSlots();
+            try (TimerCloseable t = AllocateSlotsTimer.start()) {
+                allocateStackSlots();
+            }
             if (Debug.isDumpEnabled()) {
                 dumpIntervals("After stack slot allocation");
             }
 
             // step 5: assign stack slots
-            assignStackSlots();
+            try (TimerCloseable t = AssignSlotsTimer.start()) {
+                assignStackSlots(usePos);
+            }
             Debug.dump(lir, "After StackSlot assignment");
             if (Debug.isMeterEnabled()) {
                 StackSlotAllocator.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize);
@@ -148,8 +167,8 @@
         // step 2: build intervals
         // ====================
 
-        private void buildIntervals() {
-            new FixPointIntervalBuilder(lir, stackSlotMap, maxOpId()).build();
+        private Set<LIRInstruction> buildIntervals() {
+            return new FixPointIntervalBuilder(lir, stackSlotMap, maxOpId()).build();
         }
 
         // ====================
@@ -335,16 +354,14 @@
         // step 5: assign stack slots
         // ====================
 
-        private void assignStackSlots() {
-            for (AbstractBlock<?> block : sortedBlocks) {
-                lir.getLIRforBlock(block).forEach(op -> {
-                    op.forEachInput(this::assignSlot);
-                    op.forEachAlive(this::assignSlot);
-                    op.forEachState(this::assignSlot);
+        private void assignStackSlots(Set<LIRInstruction> usePos) {
+            for (LIRInstruction op : usePos) {
+                op.forEachInput(this::assignSlot);
+                op.forEachAlive(this::assignSlot);
+                op.forEachState(this::assignSlot);
 
-                    op.forEachTemp(this::assignSlot);
-                    op.forEachOutput(this::assignSlot);
-                });
+                op.forEachTemp(this::assignSlot);
+                op.forEachOutput(this::assignSlot);
             }
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -39,14 +39,19 @@
 @NodeInfo
 public abstract class CompareNode extends BinaryOpLogicNode {
 
+    protected final Condition condition;
+    protected final boolean unorderedIsTrue;
+
     /**
      * Constructs a new Compare instruction.
      *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
-    public CompareNode(ValueNode x, ValueNode y) {
+    public CompareNode(Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
         super(x, y);
+        this.condition = condition;
+        this.unorderedIsTrue = unorderedIsTrue;
     }
 
     /**
@@ -54,14 +59,18 @@
      *
      * @return the condition
      */
-    public abstract Condition condition();
+    public final Condition condition() {
+        return condition;
+    }
 
     /**
      * Checks whether unordered inputs mean true or false (only applies to float operations).
      *
      * @return {@code true} if unordered inputs produce true
      */
-    public abstract boolean unorderedIsTrue();
+    public final boolean unorderedIsTrue() {
+        return this.unorderedIsTrue;
+    }
 
     private ValueNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
         Constant trueConstant = conditionalNode.trueValue().asConstant();
@@ -93,8 +102,10 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && forY.isConstant()) {
-            return LogicConstantNode.forBoolean(condition().foldCondition(forX.asConstant(), forY.asConstant(), tool.getConstantReflection(), unorderedIsTrue()));
+        ConstantReflectionProvider constantReflection = tool.getConstantReflection();
+        LogicNode constantCondition = tryConstantFold(condition(), forX, forY, constantReflection, unorderedIsTrue());
+        if (constantCondition != null) {
+            return constantCondition;
         }
         ValueNode result;
         if (forX.isConstant()) {
@@ -115,7 +126,14 @@
         return this;
     }
 
-    protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY);
+    public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
+        if (forX.isConstant() && forY.isConstant() && constantReflection != null) {
+            return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue));
+        }
+        return null;
+    }
+
+    protected abstract LogicNode duplicateModified(ValueNode newX, ValueNode newY);
 
     protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
         if (nonConstant instanceof ConditionalNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -31,22 +32,21 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
-public class FloatEqualsNode extends CompareNode {
+public final class FloatEqualsNode extends CompareNode {
 
     public FloatEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.EQ, false, x, y);
         assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp : x.stamp() + " " + y.stamp();
         assert x.stamp().isCompatible(y.stamp());
     }
 
-    @Override
-    public Condition condition() {
-        return Condition.EQ;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            return new FloatEqualsNode(x, y);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -33,23 +33,10 @@
 @NodeInfo(shortName = "<")
 public class FloatLessThanNode extends CompareNode {
 
-    protected final boolean unorderedIsTrue;
-
     public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
-        super(x, y);
+        super(Condition.LT, unorderedIsTrue, x, y);
         assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp;
         assert x.stamp().isCompatible(y.stamp());
-        this.unorderedIsTrue = unorderedIsTrue;
-    }
-
-    @Override
-    public Condition condition() {
-        return Condition.LT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return unorderedIsTrue;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -33,22 +33,12 @@
 public class IntegerBelowNode extends CompareNode {
 
     public IntegerBelowNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.BT, false, x, y);
         assert x.stamp() instanceof IntegerStamp;
         assert y.stamp() instanceof IntegerStamp;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.BT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         ValueNode result = super.canonical(tool, forX, forY);
         if (result != this) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -35,22 +35,12 @@
 public class IntegerEqualsNode extends CompareNode {
 
     public IntegerEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.EQ, false, x, y);
         assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
         assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.EQ;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         PrimitiveConstant primitive = (PrimitiveConstant) constant;
         if (primitive.getKind() == Kind.Int && primitive.asInt() == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -35,22 +35,12 @@
 public class IntegerLessThanNode extends CompareNode {
 
     public IntegerLessThanNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.LT, false, x, y);
         assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
         assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.LT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         PrimitiveConstant primitive = (PrimitiveConstant) constant;
         assert condition() == Condition.LT;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -55,7 +55,7 @@
         LogicNode equalComp;
         LogicNode lessComp;
         if (getX().stamp() instanceof FloatStamp) {
-            equalComp = graph().unique(new FloatEqualsNode(getX(), getY()));
+            equalComp = graph().unique(FloatEqualsNode.create(getX(), getY(), tool.getConstantReflection()));
             lessComp = graph().unique(new FloatLessThanNode(getX(), getY(), isUnorderedLess));
         } else {
             equalComp = graph().unique(new IntegerEqualsNode(getX(), getY()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -38,6 +39,15 @@
         assert y.stamp() instanceof AbstractObjectStamp;
     }
 
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            return new ObjectEqualsNode(x, y);
+        }
+    }
+
     private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
         if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) {
             if (other.isConstant()) {
@@ -75,7 +85,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 * 
+                 *
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -33,22 +33,12 @@
 public class PointerEqualsNode extends CompareNode {
 
     public PointerEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.EQ, false, x, y);
         assert x.stamp() instanceof AbstractPointerStamp;
         assert y.stamp() instanceof AbstractPointerStamp;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.EQ;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
             return LogicConstantNode.tautology();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/BlackholeNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -0,0 +1,71 @@
+/*
+ * 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.nodes.debug;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo
+public final class BlackholeNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input ValueNode value;
+
+    public BlackholeNode(ValueNode value) {
+        super(StampFactory.forVoid());
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().emitBlackhole(gen.operand(value));
+    }
+
+    @NodeIntrinsic
+    public static native void consume(boolean v);
+
+    @NodeIntrinsic
+    public static native void consume(byte v);
+
+    @NodeIntrinsic
+    public static native void consume(short v);
+
+    @NodeIntrinsic
+    public static native void consume(char v);
+
+    @NodeIntrinsic
+    public static native void consume(int v);
+
+    @NodeIntrinsic
+    public static native void consume(long v);
+
+    @NodeIntrinsic
+    public static native void consume(float v);
+
+    @NodeIntrinsic
+    public static native void consume(double v);
+
+    @NodeIntrinsic
+    public static native void consume(Object v);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -40,11 +40,18 @@
 
     protected Unique unique;
 
-    public ControlFlowAnchorNode(@SuppressWarnings("unused") Invoke invoke) {
+    public ControlFlowAnchorNode() {
         super(StampFactory.forVoid());
         this.unique = new Unique();
     }
 
+    /**
+     * Used by MacroSubstitution.
+     */
+    public ControlFlowAnchorNode(@SuppressWarnings("unused") Invoke invoke) {
+        this();
+    }
+
     public void generate(NodeLIRBuilderTool generator) {
         // do nothing
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/OpaqueNode.java	Wed Feb 04 16:38:09 2015 -0800
@@ -0,0 +1,71 @@
+/*
+ * 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.nodes.debug;
+
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo
+public class OpaqueNode extends FloatingNode implements LIRLowerable {
+
+    @Input ValueNode value;
+
+    public OpaqueNode(ValueNode value) {
+        super(value.stamp().unrestricted());
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.operand(value));
+    }
+
+    @NodeIntrinsic
+    public static native boolean opaque(boolean v);
+
+    @NodeIntrinsic
+    public static native byte opaque(byte v);
+
+    @NodeIntrinsic
+    public static native short opaque(short v);
+
+    @NodeIntrinsic
+    public static native char opaque(char v);
+
+    @NodeIntrinsic
+    public static native int opaque(int v);
+
+    @NodeIntrinsic
+    public static native long opaque(long v);
+
+    @NodeIntrinsic
+    public static native float opaque(float v);
+
+    @NodeIntrinsic
+    public static native double opaque(double v);
+
+    @NodeIntrinsic
+    public static native <T> T opaque(T v);
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java	Wed Feb 04 16:38:09 2015 -0800
@@ -23,7 +23,7 @@
 package com.oracle.graal.replacements;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 
 /**
  * Substitutions for both the old and new versions of JMH Blackhole helper classes.
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java	Wed Feb 04 16:38:09 2015 -0800
@@ -29,7 +29,6 @@
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(GraalDirectives.class)
 public class GraalDirectivesSubstitutions {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Feb 04 16:38:09 2015 -0800
@@ -619,8 +619,8 @@
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(
-                                    graph);
+                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, replacements.providers.getConstantReflection(),
+                                    GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
                 }
                 afterParsing(graph);
 
@@ -633,9 +633,9 @@
             return graph;
         }
 
-        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts) {
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
+        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, constantReflectionProvider, graphBuilderConfig, optimisticOpts);
         }
 
         protected void afterParsing(StructuredGraph graph) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * 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.nodes;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo
-public final class BlackholeNode extends FixedWithNextNode implements LIRLowerable {
-
-    @Input ValueNode value;
-
-    public BlackholeNode(ValueNode value) {
-        super(StampFactory.forVoid());
-        this.value = value;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        gen.getLIRGeneratorTool().emitBlackhole(gen.operand(value));
-    }
-
-    @NodeIntrinsic
-    public static native void consume(boolean v);
-
-    @NodeIntrinsic
-    public static native void consume(byte v);
-
-    @NodeIntrinsic
-    public static native void consume(short v);
-
-    @NodeIntrinsic
-    public static native void consume(char v);
-
-    @NodeIntrinsic
-    public static native void consume(int v);
-
-    @NodeIntrinsic
-    public static native void consume(long v);
-
-    @NodeIntrinsic
-    public static native void consume(float v);
-
-    @NodeIntrinsic
-    public static native void consume(double v);
-
-    @NodeIntrinsic
-    public static native void consume(Object v);
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/OpaqueNode.java	Wed Feb 04 16:34:07 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * 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.nodes;
-
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo
-public class OpaqueNode extends FloatingNode implements LIRLowerable {
-
-    @Input ValueNode value;
-
-    public OpaqueNode(ValueNode value) {
-        super(value.stamp().unrestricted());
-        this.value = value;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.operand(value));
-    }
-
-    @NodeIntrinsic
-    public static native boolean opaque(boolean v);
-
-    @NodeIntrinsic
-    public static native byte opaque(byte v);
-
-    @NodeIntrinsic
-    public static native short opaque(short v);
-
-    @NodeIntrinsic
-    public static native char opaque(char v);
-
-    @NodeIntrinsic
-    public static native int opaque(int v);
-
-    @NodeIntrinsic
-    public static native long opaque(long v);
-
-    @NodeIntrinsic
-    public static native float opaque(float v);
-
-    @NodeIntrinsic
-    public static native double opaque(double v);
-
-    @NodeIntrinsic
-    public static native <T> T opaque(T v);
-}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Feb 04 16:38:09 2015 -0800
@@ -177,7 +177,8 @@
         Suites suites = suitesProvider.createSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
+                        OptimisticOptimizations.ALL).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Feb 04 16:38:09 2015 -0800
@@ -36,9 +36,11 @@
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
+import com.oracle.graal.java.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -70,15 +72,26 @@
     private final TruffleCache truffleCache;
     private final SnippetReflectionProvider snippetReflection;
     private final ResolvedJavaMethod callDirectMethod;
+    private final ResolvedJavaMethod callInlinedMethod;
     private final ResolvedJavaMethod callSiteProxyMethod;
+    protected final ResolvedJavaMethod callRootMethod;
+    private final GraphBuilderConfiguration configForRoot;
 
-    public PartialEvaluator(Providers providers, TruffleCache truffleCache, SnippetReflectionProvider snippetReflection) {
+    public PartialEvaluator(Providers providers, GraphBuilderConfiguration configForRoot, TruffleCache truffleCache, SnippetReflectionProvider snippetReflection) {
         this.providers = providers;
         this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
         this.snippetReflection = snippetReflection;
         this.truffleCache = truffleCache;
         this.callDirectMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod());
+        this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod());
         this.callSiteProxyMethod = providers.getMetaAccess().lookupJavaMethod(GraalFrameInstance.CallNodeFrame.METHOD);
+        this.configForRoot = configForRoot;
+
+        try {
+            callRootMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class));
+        } catch (NoSuchMethodException ex) {
+            throw new RuntimeException(ex);
+        }
     }
 
     public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) {
@@ -91,65 +104,34 @@
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
-        final StructuredGraph graph = truffleCache.createRootGraph(callTarget.toString());
+
+        final StructuredGraph graph = new StructuredGraph(callTarget.toString(), callRootMethod);
         assert graph != null : "no graph for root method";
 
         try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph)) {
-            // Canonicalize / constant propagate.
-            PhaseContext baseContext = new PhaseContext(providers, assumptions);
-
-            injectConstantCallTarget(graph, callTarget, baseContext);
-
-            Debug.dump(graph, "Before expansion");
-
-            TruffleExpansionLogger expansionLogger = null;
-            if (TraceTruffleExpansion.getValue()) {
-                expansionLogger = new TruffleExpansionLogger(providers, graph);
-            }
 
-            expandTree(graph, assumptions, expansionLogger);
+            Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
+            if (CacheGraphs.getValue()) {
+                graphCache = new HashMap<>();
+            }
+            PhaseContext baseContext = new PhaseContext(providers, assumptions);
+            HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
 
-            TruffleInliningCache inliningCache = null;
-            if (TruffleFunctionInlining.getValue()) {
-                callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-                if (TruffleFunctionInliningCache.getValue()) {
-                    inliningCache = new TruffleInliningCache();
-                }
+            if (TruffleCompilerOptions.FastPE.getValue()) {
+                fastPartialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
+            } else {
+                createRootGraph(graph);
+                partialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
             }
 
-            expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache);
-
             if (Thread.currentThread().isInterrupted()) {
                 return null;
             }
 
             new VerifyFrameDoesNotEscapePhase().apply(graph, false);
-
             if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) {
                 createHistogram();
             }
-
-            canonicalizer.apply(graph, baseContext);
-            Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
-            if (CacheGraphs.getValue()) {
-                graphCache = new HashMap<>();
-            }
-            HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
-
-            // EA frame and clean up.
-            do {
-                try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
-                    new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
-                    new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext);
-                } catch (Throwable t) {
-                    Debug.handle(t);
-                }
-            } while (expandTree(graph, assumptions, expansionLogger));
-
-            if (expansionLogger != null) {
-                expansionLogger.print(callTarget);
-            }
-
             postPartialEvaluation(graph);
 
         } catch (Throwable e) {
@@ -159,6 +141,104 @@
         return graph;
     }
 
+    private class InterceptLoadFieldPlugin implements GraphBuilderPlugins.LoadFieldPlugin {
+
+        public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+            System.out.println("Load field plugin called for receiver: " + receiver + " and field " + field);
+
+            if (receiver.isConstant()) {
+                JavaConstant asJavaConstant = receiver.asJavaConstant();
+                JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant);
+                if (result != null) {
+                    ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess()));
+                    builder.push(constantNode.getKind(), constantNode);
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private class InterceptReceiverPlugin implements GraphBuilderPlugins.ParameterPlugin {
+
+        private final Object receiver;
+
+        public InterceptReceiverPlugin(Object receiver) {
+            this.receiver = receiver;
+        }
+
+        public FloatingNode interceptParameter(int index) {
+            if (index == 0) {
+                return ConstantNode.forConstant(snippetReflection.forObject(receiver), providers.getMetaAccess());
+            }
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void fastPartialEvaluation(OptimizedCallTarget callTarget, Assumptions assumptions, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
+        GraphBuilderConfiguration newConfig = configForRoot.copy();
+        newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
+        newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations).apply(graph);
+        Debug.dump(graph, "After FastPE");
+    }
+
+    private void partialEvaluation(final OptimizedCallTarget callTarget, final Assumptions assumptions, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
+        injectConstantCallTarget(graph, callTarget, baseContext);
+
+        Debug.dump(graph, "Before expansion");
+
+        TruffleExpansionLogger expansionLogger = null;
+        if (TraceTruffleExpansion.getValue()) {
+            expansionLogger = new TruffleExpansionLogger(providers, graph);
+        }
+
+        expandTree(graph, assumptions, expansionLogger);
+
+        TruffleInliningCache inliningCache = null;
+        if (TruffleFunctionInlining.getValue()) {
+            callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
+            if (TruffleFunctionInliningCache.getValue()) {
+                inliningCache = new TruffleInliningCache();
+            }
+        }
+
+        expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache);
+
+        if (Thread.currentThread().isInterrupted()) {
+            return;
+        }
+
+        canonicalizer.apply(graph, baseContext);
+        // EA frame and clean up.
+        do {
+            try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
+                new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
+                new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext);
+            } catch (Throwable t) {
+                Debug.handle(t);
+            }
+        } while (expandTree(graph, assumptions, expansionLogger));
+
+        if (expansionLogger != null) {
+            expansionLogger.print(callTarget);
+        }
+    }
+
+    public StructuredGraph createRootGraph(StructuredGraph graph) {
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot,
+                        TruffleCompilerImpl.Optimizations).apply(graph);
+        return graph;
+    }
+
+    public StructuredGraph createInlineGraph(String name) {
+        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot,
+                        TruffleCompilerImpl.Optimizations).apply(graph);
+        return graph;
+    }
+
     private static void postPartialEvaluation(final StructuredGraph graph) {
         NeverPartOfCompilationNode.verifyNotFoundIn(graph);
         for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
@@ -464,7 +544,7 @@
     private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, TruffleInliningDecision decision) {
         try (Scope s = Debug.scope("GuestLanguageInlinedGraph", new DebugDumpScope(decision.getTarget().toString()))) {
             OptimizedCallTarget target = decision.getTarget();
-            StructuredGraph inlineGraph = truffleCache.createInlineGraph(target.toString());
+            StructuredGraph inlineGraph = createInlineGraph(target.toString());
             injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext);
             TruffleExpansionLogger expansionLogger = null;
             if (TraceTruffleExpansion.getValue()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Wed Feb 04 16:38:09 2015 -0800
@@ -30,13 +30,6 @@
 public interface TruffleCache {
 
     /**
-     * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#callBoundary}.
-     */
-    StructuredGraph createRootGraph(String name);
-
-    StructuredGraph createInlineGraph(String name);
-
-    /**
      * Returns a cached graph for a method with given arguments.
      */
     StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final CanonicalizerPhase finalCanonicalizer);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Feb 04 16:38:09 2015 -0800
@@ -56,7 +56,6 @@
 
     private final Providers providers;
     private final GraphBuilderConfiguration config;
-    private final GraphBuilderConfiguration configForRoot;
     private final OptimisticOptimizations optimisticOptimizations;
 
     private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
@@ -68,40 +67,17 @@
     private final ResolvedJavaType errorClass;
     private final ResolvedJavaType controlFlowExceptionClass;
 
-    protected final ResolvedJavaMethod callRootMethod;
-    protected final ResolvedJavaMethod callInlinedMethod;
-
     private long counter;
 
-    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRoot, OptimisticOptimizations optimisticOptimizations) {
+    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) {
         this.providers = providers;
         this.config = config;
-        this.configForRoot = configForRoot;
         this.optimisticOptimizations = optimisticOptimizations;
 
         this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class);
         this.runtimeExceptionClass = providers.getMetaAccess().lookupJavaType(RuntimeException.class);
         this.errorClass = providers.getMetaAccess().lookupJavaType(Error.class);
         this.controlFlowExceptionClass = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
-
-        try {
-            callRootMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class));
-        } catch (NoSuchMethodException ex) {
-            throw new RuntimeException(ex);
-        }
-        this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod());
-    }
-
-    public StructuredGraph createInlineGraph(String name) {
-        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), config, TruffleCompilerImpl.Optimizations).apply(graph);
-        return graph;
-    }
-
-    public StructuredGraph createRootGraph(String name) {
-        StructuredGraph graph = new StructuredGraph(name, callRootMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
-        return graph;
     }
 
     private static List<Object> computeCacheKey(ResolvedJavaMethod method, NodeInputList<ValueNode> arguments) {
@@ -294,7 +270,7 @@
 
     protected StructuredGraph parseGraph(final ResolvedJavaMethod method, final PhaseContext phaseContext) {
         final StructuredGraph graph = new StructuredGraph(method);
-        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), config, optimisticOptimizations).apply(graph);
+        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), null, config, optimisticOptimizations).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Feb 04 16:38:09 2015 -0800
@@ -84,9 +84,9 @@
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
         this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
-        this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations);
+        this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, TruffleCompilerImpl.Optimizations);
 
-        this.partialEvaluator = new PartialEvaluator(providers, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class));
+        this.partialEvaluator = new PartialEvaluator(providers, config, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class));
 
         if (Debug.isEnabled()) {
             DebugEnvironment.initialize(System.out);
@@ -197,8 +197,9 @@
     private PhaseSuite<HighTierContext> createGraphBuilderSuite() {
         PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
+        GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) iterator.previous();
         iterator.remove();
-        iterator.add(new GraphBuilderPhase(config));
+        iterator.add(new GraphBuilderPhase(config, graphBuilderPhase.getGraphBuilderPlugins()));
         return suite;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Wed Feb 04 16:34:07 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Wed Feb 04 16:38:09 2015 -0800
@@ -28,6 +28,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.truffle.nodes.frame.*;
@@ -39,96 +41,69 @@
 @ServiceProvider(GraphBuilderPluginsProvider.class)
 public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
     public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, CompilerDirectivesPlugin.class);
-    }
-
-    /**
-     * Plugins for {@link CompilerDirectives}.
-     */
-    enum CompilerDirectivesPlugin implements GraphBuilderPlugin {
-        inInterpreter() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(ConstantNode.forBoolean(false));
+        Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class);
+        r.register0("inInterpreter", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(false)));
                 return true;
             }
-        },
-        inCompiledCode() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(ConstantNode.forBoolean(true));
+        });
+        r.register0("inCompiledCode", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
                 return true;
             }
-        },
-        transferToInterpreter() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register0("transferToInterpreter", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
                 builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
-        },
-        transferToInterpreterAndInvalidate() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
                 builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
-        },
-        interpreterOnly(Runnable.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
                 return true;
             }
-        },
-        interpreterOnly$(Callable.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register1("interpreterOnly", Callable.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
                 return true;
             }
-        },
-        injectBranchProbability(double.class, boolean.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode probability = args[0];
-                ValueNode condition = args[1];
+        });
+        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
                 builder.append(new BranchProbabilityNode(probability, condition));
                 return true;
             }
-        },
-        bailout(String.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                // TODO: is this too eager? Should a BailoutNode be created instead?
-                ValueNode message = args[0];
+        });
+        r.register1("bailout", String.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode message) {
                 if (message.isConstant()) {
                     throw new BailoutException(message.asConstant().toValueString());
                 }
                 throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)");
             }
-        },
-
-        isCompilationConstant(Object.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode arg0 = args[0];
-                if (arg0 instanceof BoxNode) {
-                    arg0 = ((BoxNode) arg0).getValue();
-                }
-                if (arg0.isConstant()) {
+        });
+        r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
                     builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
                     return true;
                 }
-
-                // Cannot create MacroNodes in a plugin (yet)
                 return false;
             }
-        },
-        materialize(Object.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(new ForceMaterializeNode(args[0]));
+        });
+        r.register1("materialize", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.append(new ForceMaterializeNode(value));
                 return true;
             }
-        };
-
-        CompilerDirectivesPlugin(Class<?>... parameterTypes) {
-            this.parameterTypes = parameterTypes;
-        }
-
-        private final Class<?>[] parameterTypes;
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            return GraphBuilderPlugin.resolveTarget(metaAccess, CompilerDirectives.class, name(), parameterTypes);
-        }
+        });
     }
 }
--- a/mx/suite.py	Wed Feb 04 16:34:07 2015 -0800
+++ b/mx/suite.py	Wed Feb 04 16:38:09 2015 -0800
@@ -601,7 +601,6 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.graal.api.directives",
         "com.oracle.graal.compiler",
         "com.oracle.graal.java",
         "com.oracle.graal.word",
@@ -815,6 +814,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.phases",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -875,7 +875,6 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.graal.api.directives",
         "com.oracle.graal.test",
         "com.oracle.graal.printer",
         "com.oracle.graal.runtime",