changeset 19922:815a87264cbb

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Tue, 17 Mar 2015 11:23:06 -0700
parents ea280aa54d58 (current diff) fc1e46a702a1 (diff)
children 470fb57cfb31
files graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java
diffstat 101 files changed, 2861 insertions(+), 1641 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Mar 17 11:23:06 2015 -0700
@@ -1943,6 +1943,10 @@
         ADD.rmOp.emit(this, QWORD, dst, src);
     }
 
+    public final void addq(AMD64Address dst, Register src) {
+        ADD.mrOp.emit(this, QWORD, dst, src);
+    }
+
     public final void andq(Register dst, int imm32) {
         AND.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Tue Mar 17 11:23:06 2015 -0700
@@ -41,6 +41,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -68,7 +70,8 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
 
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getEagerDefault()));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(new Plugins(new InvocationPlugins(metaAccess)));
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, null, graphBuilderSuite, OptimisticOptimizations.NONE);
 
         Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -28,10 +28,11 @@
 
 import org.junit.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.meta.Assumptions.NoFinalizableSubclass;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
@@ -66,7 +67,7 @@
         final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]);
         StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
 
-        GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
+        GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins());
         new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL, null).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -48,6 +48,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
@@ -61,7 +63,7 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
-import com.oracle.graal.phases.schedule.SchedulePhase.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.printer.*;
@@ -773,7 +775,7 @@
     }
 
     /**
-     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault() default} mode to
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to
      * produce a graph.
      *
      * @param methodName the name of the method in {@code this.getClass()} to be parsed
@@ -783,7 +785,7 @@
     }
 
     /**
-     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault() default} mode to
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to
      * produce a graph.
      */
     protected StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
@@ -791,8 +793,8 @@
     }
 
     /**
-     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getEagerDefault() eager} mode
-     * to produce a graph.
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getEagerDefault eager} mode to
+     * produce a graph.
      *
      * @param methodName the name of the method in {@code this.getClass()} to be parsed
      */
@@ -801,19 +803,19 @@
     }
 
     /**
-     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getEagerDefault() eager} mode
-     * to produce a graph.
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getEagerDefault eager} mode to
+     * produce a graph.
      */
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerDefault()), allowAssumptions);
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerDefault(getDefaultGraphBuilderPlugins())), allowAssumptions);
     }
 
     /**
-     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getFullDebugDefault() full
-     * debug} mode to produce a graph.
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getFullDebugDefault full debug}
+     * mode to produce a graph.
      */
     protected StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()), allowAssumptions);
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault(getDefaultGraphBuilderPlugins())), allowAssumptions);
     }
 
     private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, AllowAssumptions allowAssumptions) {
@@ -827,32 +829,31 @@
         }
     }
 
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite();
+        Plugins defaultPlugins = ((GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous()).getGraphBuilderConfig().getPlugins();
+        // defensive copying
+        return new Plugins(defaultPlugins);
+    }
+
     protected PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
         // defensive copying
         return backend.getSuites().getDefaultGraphBuilderSuite().copy();
     }
 
     protected PhaseSuite<HighTierContext> getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) {
-        PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite().copy();
+        PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite();
         ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
-        GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) iterator.previous();
-        GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy().copyPluginsFrom(graphBuilderPhase.getGraphBuilderConfig()));
+        GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy());
         iterator.remove();
         iterator.add(new GraphBuilderPhase(gbConfCopy));
         return suite;
     }
 
     protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        editGraphBuilderPlugins(conf.getPlugins());
         return conf;
     }
 
-    /**
-     * @param plugins
-     */
-    protected void editGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
-    }
-
     protected Replacements getReplacements() {
         return getProviders().getReplacements();
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -34,7 +34,7 @@
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
@@ -84,7 +84,7 @@
         }
         assertTrue(graphLineSPs > 0);
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault());
+        PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault(getDefaultGraphBuilderPlugins()));
         final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL,
                         getProfilingInfo(graph), getSpeculationLog(), getSuites(), getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         int lineSPs = 0;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -282,9 +282,42 @@
     }
 
     /**
+     * Here the read should not float out of the loop.
+     */
+    public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+                for (int k = 0; k < a; ++k) {
+                    if (k % 2 == 1) {
+                        for (int j = 0; j < b; ++j) {
+                            obj.hash = 3;
+                        }
+                    }
+                }
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop7() {
+        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(18, schedule.getCFG().getBlocks().size());
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
      * Here the read should not float to the end.
      */
-    public static int testLoop7Snippet(int a, int b) {
+    public static int testLoop8Snippet(int a, int b) {
         int result = container.a;
         for (int i = 0; i < a; i++) {
             if (b < 0) {
@@ -301,8 +334,8 @@
     }
 
     @Test
-    public void testLoop7() {
-        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+    public void testLoop8() {
+        SchedulePhase schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,114 @@
+/*
+ * 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.compiler.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.DeoptimizingNode.DeoptDuring;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
+import com.oracle.graal.phases.tiers.*;
+
+public class SchedulingTest2 extends GraphScheduleTest {
+
+    public static int testSnippet() {
+        return test() + 2;
+    }
+
+    public static int test() {
+        return 40;
+    }
+
+    @Test
+    public void testValueProxyInputs() {
+        StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES);
+        ReturnNode returnNode = graph.getNodes(ReturnNode.TYPE).first();
+        BeginNode beginNode = graph.add(new BeginNode());
+        returnNode.replaceAtPredecessor(beginNode);
+        beginNode.setNext(returnNode);
+        Debug.dump(graph, "Graph");
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
+        NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
+        assertDeepEquals(2, schedule.getCFG().getBlocks().size());
+        for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
+            if (node instanceof AddNode) {
+                assertTrue(node.toString() + " expected: " + nodeToBlock.get(beginNode) + " but was: " + nodeToBlock.get(node), nodeToBlock.get(node) == nodeToBlock.get(beginNode));
+            }
+        }
+
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            Block block = nodeToBlock.get(fs);
+            assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock());
+            for (Node usage : fs.usages()) {
+                if (usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) {
+                    assertTrue(usage.toString(), nodeToBlock.get(usage) == block);
+                    if (usage != block.getBeginNode()) {
+                        List<Node> map = blockToNodesMap.get(block);
+                        assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage));
+                    }
+                }
+            }
+        }
+
+        PhaseContext context = new PhaseContext(getProviders());
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+        MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+
+        new GuardLoweringPhase().apply(graph, midContext);
+        FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase();
+        phase.apply(graph);
+
+        schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        blockToNodesMap = schedule.getBlockToNodesMap();
+        nodeToBlock = schedule.getNodeToBlockMap();
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            Block block = nodeToBlock.get(fs);
+            assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock());
+            for (Node usage : fs.usages()) {
+                if ((usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) || (usage instanceof DeoptDuring && ((DeoptDuring) usage).stateDuring() == fs)) {
+                    assertTrue(usage.toString(), nodeToBlock.get(usage) == block);
+                    if (usage != block.getBeginNode()) {
+                        List<Node> map = blockToNodesMap.get(block);
+                        assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage));
+                    }
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -30,7 +30,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.java.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
@@ -231,7 +231,8 @@
         try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet))) {
             ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
             StructuredGraph graph = eagerInfopointMode ? parseDebug(method, AllowAssumptions.YES) : parseEager(method, AllowAssumptions.YES);
-            PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()) : getDefaultGraphBuilderSuite();
+            PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault(getDefaultGraphBuilderPlugins()))
+                            : getDefaultGraphBuilderSuite();
             HighTierContext context = new HighTierContext(getProviders(), null, graphBuilderSuite, OptimisticOptimizations.ALL);
             Debug.dump(graph, "Graph");
             new CanonicalizerPhase().apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Mar 17 11:23:06 2015 -0700
@@ -29,6 +29,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
@@ -222,7 +224,7 @@
                      * the code before static analysis, the classes would otherwise be not loaded
                      * yet and the bytecode parser would only create a graph.
                      */
-                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault();
+                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault(new Plugins(new InvocationPlugins(metaAccess)));
                     /*
                      * For simplicity, we ignore all exception handling during the static analysis.
                      * This is a constraint of this example code, a real static analysis needs to
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Mar 17 11:23:06 2015 -0700
@@ -346,7 +346,7 @@
         AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory());
         lirSuites.getAllocationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, allocContext);
 
-        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext();
+        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
         lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, postAllocOptContext);
 
         return lirGenRes;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GenericInvocationPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Plugin for handling an invocation based on some property of the method being invoked such as any
+ * annotations it may have.
+ */
+public interface GenericInvocationPlugin extends GraphBuilderPlugin {
+    /**
+     * Executes this plugin for an invocation of a given method with a given set of arguments.
+     *
+     * @return {@code true} if this plugin handled the invocation, {@code false} if not
+     */
+    boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graphbuilderconf;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
+
+public class GraphBuilderConfiguration {
+
+    public static class Plugins {
+        private final InvocationPlugins invocationPlugins;
+        private LoadFieldPlugin loadFieldPlugin;
+        private LoadIndexedPlugin loadIndexedPlugin;
+        private ParameterPlugin parameterPlugin;
+        private InlineInvokePlugin inlineInvokePlugin;
+        private GenericInvocationPlugin genericInvocationPlugin;
+        private LoopExplosionPlugin loopExplosionPlugin;
+
+        /**
+         * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in
+         * {@code copyFrom} become the {@linkplain InvocationPlugins#getParent() default}
+         * {@linkplain #getInvocationPlugins() invocation plugins} in this object.
+         */
+        public Plugins(Plugins copyFrom) {
+            this.invocationPlugins = new InvocationPlugins(copyFrom.invocationPlugins);
+            this.parameterPlugin = copyFrom.parameterPlugin;
+            this.loadFieldPlugin = copyFrom.loadFieldPlugin;
+            this.loadIndexedPlugin = copyFrom.loadIndexedPlugin;
+            this.inlineInvokePlugin = copyFrom.inlineInvokePlugin;
+            this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
+            this.genericInvocationPlugin = copyFrom.genericInvocationPlugin;
+        }
+
+        /**
+         * Creates a new set of plugins.
+         *
+         * @param invocationPlugins the {@linkplain #getInvocationPlugins() invocation plugins} in
+         *            this object
+         */
+        public Plugins(InvocationPlugins invocationPlugins) {
+            this.invocationPlugins = invocationPlugins;
+        }
+
+        public InvocationPlugins getInvocationPlugins() {
+            return invocationPlugins;
+        }
+
+        public GenericInvocationPlugin getGenericInvocationPlugin() {
+            return genericInvocationPlugin;
+        }
+
+        public void setGenericInvocationPlugin(GenericInvocationPlugin plugin) {
+            this.genericInvocationPlugin = plugin;
+        }
+
+        public LoadFieldPlugin getLoadFieldPlugin() {
+            return loadFieldPlugin;
+        }
+
+        public void setLoadFieldPlugin(LoadFieldPlugin plugin) {
+            this.loadFieldPlugin = plugin;
+        }
+
+        public LoadIndexedPlugin getLoadIndexedPlugin() {
+            return loadIndexedPlugin;
+        }
+
+        public void setLoadIndexedPlugin(LoadIndexedPlugin plugin) {
+            this.loadIndexedPlugin = plugin;
+        }
+
+        public ParameterPlugin getParameterPlugin() {
+            return parameterPlugin;
+        }
+
+        public void setParameterPlugin(ParameterPlugin plugin) {
+            this.parameterPlugin = plugin;
+        }
+
+        public InlineInvokePlugin getInlineInvokePlugin() {
+            return inlineInvokePlugin;
+        }
+
+        public void setInlineInvokePlugin(InlineInvokePlugin plugin) {
+            this.inlineInvokePlugin = plugin;
+        }
+
+        public LoopExplosionPlugin getLoopExplosionPlugin() {
+            return loopExplosionPlugin;
+        }
+
+        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
+            this.loopExplosionPlugin = plugin;
+        }
+    }
+
+    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
+
+    private final boolean eagerResolving;
+    private final boolean omitAllExceptionEdges;
+    private final ResolvedJavaType[] skippedExceptionTypes;
+    private final DebugInfoMode debugInfoMode;
+    private final boolean doLivenessAnalysis;
+    private boolean useProfiling;
+    private final Plugins plugins;
+
+    public static enum DebugInfoMode {
+        SafePointsOnly,
+        /**
+         * This mode inserts {@link SimpleInfopointNode}s in places where no safepoints would be
+         * inserted: inlining boundaries, and line number switches.
+         * <p>
+         * In this mode the infopoint only have a location (method and bytecode index) and no
+         * values.
+         * <p>
+         * This is useful to have better program counter to bci mapping and has no influence on the
+         * generated code. However it can increase the amount of metadata and does not allow access
+         * to accessing values at runtime.
+         */
+        Simple,
+        /**
+         * In this mode, {@link FullInfopointNode}s are generated in the same locations as in
+         * {@link #Simple} mode but the infopoints have access to the runtime values.
+         * <p>
+         * This is relevant when code is to be generated for native, machine-code level debugging
+         * but can have a limit the amount of optimization applied to the code.
+         */
+        Full,
+    }
+
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis,
+                    Plugins plugins) {
+        this.eagerResolving = eagerResolving;
+        this.omitAllExceptionEdges = omitAllExceptionEdges;
+        this.debugInfoMode = debugInfoMode;
+        this.skippedExceptionTypes = skippedExceptionTypes;
+        this.doLivenessAnalysis = doLivenessAnalysis;
+        this.useProfiling = true;
+        this.plugins = plugins;
+    }
+
+    /**
+     * Creates a copy of this configuration with all its plugins. The {@link InvocationPlugins} in
+     * this configuration become the {@linkplain InvocationPlugins#getParent() parent} of the
+     * {@link InvocationPlugins} in the copy.
+     */
+    public GraphBuilderConfiguration copy() {
+        Plugins newPlugins = new Plugins(new InvocationPlugins(plugins.getInvocationPlugins()));
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins);
+        result.useProfiling = useProfiling;
+        return result;
+    }
+
+    public boolean getUseProfiling() {
+        return useProfiling;
+    }
+
+    public void setUseProfiling(boolean b) {
+        this.useProfiling = b;
+    }
+
+    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins);
+    }
+
+    public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
+        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, plugins);
+    }
+
+    public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
+        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins);
+    }
+
+    public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, plugins);
+    }
+
+    public ResolvedJavaType[] getSkippedExceptionTypes() {
+        return skippedExceptionTypes;
+    }
+
+    public boolean eagerResolving() {
+        return eagerResolving;
+    }
+
+    public boolean omitAllExceptionEdges() {
+        return omitAllExceptionEdges;
+    }
+
+    public boolean insertNonSafepointDebugInfo() {
+        return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
+    }
+
+    public boolean insertFullDebugInfo() {
+        return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal();
+    }
+
+    public boolean doLivenessAnalysis() {
+        return doLivenessAnalysis;
+    }
+
+    public static GraphBuilderConfiguration getDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+    }
+
+    /**
+     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
+     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
+     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
+     */
+    public boolean unresolvedIsError() {
+        return eagerResolving;
+    }
+
+    public Plugins getPlugins() {
+        return plugins;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,142 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object.
+ */
+public interface GraphBuilderContext {
+
+    /**
+     * Information about a snippet or method substitution currently being processed by the graph
+     * builder. When in the scope of a replacement, the graph builder does not check the value kinds
+     * flowing through the JVM state since replacements can employ non-Java kinds to represent
+     * values such as raw machine words and pointers.
+     */
+    public interface Replacement {
+
+        /**
+         * Gets the method being replaced.
+         */
+        ResolvedJavaMethod getOriginalMethod();
+
+        /**
+         * Gets the replacement method.
+         */
+        ResolvedJavaMethod getReplacementMethod();
+
+        /**
+         * Determines if this replacement is being inlined as a compiler intrinsic. A compiler
+         * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler
+         * intrinsic will restart the interpreter at the intrinsified call.
+         */
+        boolean isIntrinsic();
+    }
+
+    <T extends ControlSinkNode> T append(T fixed);
+
+    <T extends ControlSplitNode> T append(T fixed);
+
+    <T extends FixedWithNextNode> T append(T fixed);
+
+    <T extends FloatingNode> T append(T value);
+
+    <T extends ValueNode> T append(T value);
+
+    StampProvider getStampProvider();
+
+    MetaAccessProvider getMetaAccess();
+
+    Assumptions getAssumptions();
+
+    ConstantReflectionProvider getConstantReflection();
+
+    SnippetReflectionProvider getSnippetReflection();
+
+    void push(Kind kind, ValueNode value);
+
+    StructuredGraph getGraph();
+
+    FrameState createStateAfter();
+
+    /**
+     * Gets the parsing context for the method that inlines the method being parsed by this context.
+     */
+    GraphBuilderContext getParent();
+
+    /**
+     * Gets the root method for the graph building process.
+     */
+    ResolvedJavaMethod getRootMethod();
+
+    /**
+     * Gets the method currently being parsed.
+     */
+    ResolvedJavaMethod getMethod();
+
+    /**
+     * Gets the index of the bytecode instruction currently being parsed.
+     */
+    int bci();
+
+    /**
+     * Gets the inline depth of this context. 0 implies this is the context for the
+     * {@linkplain #getRootMethod() root method}.
+     */
+    int getDepth();
+
+    /**
+     * Determines if the current parsing context is a snippet or method substitution.
+     */
+    default boolean parsingReplacement() {
+        return getReplacement() == null;
+    }
+
+    /**
+     * Gets the replacement of the current parsing context or {@code null} if not
+     * {@link #parsingReplacement() parsing a replacement}.
+     */
+    Replacement getReplacement();
+
+    /**
+     * @see GuardingPiNode#nullCheckedValue(ValueNode)
+     */
+    static ValueNode nullCheckedValue(GraphBuilderContext builder, ValueNode value) {
+        ValueNode nonNullValue = GuardingPiNode.nullCheckedValue(value);
+        if (nonNullValue != value) {
+            builder.append((FixedWithNextNode) nonNullValue);
+        }
+        return nonNullValue;
+    }
+
+    boolean eagerResolving();
+
+    BailoutException bailout(String string);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,29 @@
+/*
+ * 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.graphbuilderconf;
+
+/**
+ * Marker interface for graph builder plugins.
+ */
+public interface GraphBuilderPlugin {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,89 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined
+ * invocations that result in {@link Invoke} nodes.
+ */
+public interface InlineInvokePlugin extends GraphBuilderPlugin {
+
+    public static class InlineInfo {
+
+        /**
+         * The method to be inlined.
+         */
+        public final ResolvedJavaMethod methodToInline;
+
+        /**
+         * Specifies if {@link #methodToInline} is to be considered a
+         * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method} passed to
+         * {@link InlineInvokePlugin#getInlineInfo}.
+         */
+        public final boolean isReplacement;
+
+        /**
+         * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, any
+         * {@link StateSplit} node created in the (recursive) inlining scope will be given a frame
+         * state that restarts the interpreter just before the intrinsified invocation.
+         */
+        public final boolean isIntrinsic;
+
+        public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) {
+            this.methodToInline = methodToInline;
+            this.isIntrinsic = isIntrinsic;
+            this.isReplacement = isReplacement;
+            assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement";
+        }
+    }
+
+    /**
+     * Determines whether a call to a given method is to be inlined.
+     *
+     * @param method the target method of an invoke
+     * @param args the arguments to the invoke
+     * @param returnType the return type derived from {@code method}'s signature
+     */
+    default InlineInvokePlugin.InlineInfo getInlineInfo(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        return null;
+    }
+
+    /**
+     * @param inlinedTargetMethod
+     */
+    default void postInline(ResolvedJavaMethod inlinedTargetMethod) {
+    }
+
+    /**
+     * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined per
+     * {@link #getInlineInfo}.
+     *
+     * @param method the method that was not inlined
+     * @param invoke the invoke node created for the call to {@code method}
+     */
+    default void notifyOfNoninlinedInvoke(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,123 @@
+/*
+ * 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.graphbuilderconf;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Plugin for handling a specific method invocation.
+ */
+public interface InvocationPlugin extends GraphBuilderPlugin {
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+        throw invalidHandler(b, targetMethod);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
+        throw invalidHandler(b, targetMethod, arg);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) {
+        throw invalidHandler(b, targetMethod, arg1, arg2);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+        throw invalidHandler(b, targetMethod, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+        throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
+        throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    default ResolvedJavaMethod getSubstitute() {
+        return null;
+    }
+
+    /**
+     * Executes a given plugin against a set of invocation arguments by dispatching to the
+     * {@code apply(...)} method that matches the number of arguments.
+     *
+     * @param targetMethod the method for which plugin is being applied
+     * @return {@code true} if the plugin handled the invocation of {@code targetMethod}
+     *         {@code false} if the graph builder should process the invoke further (e.g., by
+     *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
+     *         invocation must not modify the graph being constructed.
+     */
+    static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) {
+        if (args.length == 0) {
+            return plugin.apply(b, targetMethod);
+        } else if (args.length == 1) {
+            return plugin.apply(b, targetMethod, args[0]);
+        } else if (args.length == 2) {
+            return plugin.apply(b, targetMethod, args[0], args[1]);
+        } else if (args.length == 3) {
+            return plugin.apply(b, targetMethod, args[0], args[1], args[2]);
+        } else if (args.length == 4) {
+            return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]);
+        } else if (args.length == 5) {
+            return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]);
+        } else {
+            throw plugin.invalidHandler(b, targetMethod, args);
+        }
+    }
+
+    default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) {
+        return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
+    }
+
+    default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+        Class<?> c = getClass();
+        for (Method m : c.getDeclaredMethods()) {
+            if (m.getName().equals("apply")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            }
+        }
+        throw new GraalInternalError("could not find method named \"apply\" in " + c.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPluginIdHolder.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,42 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * {@link ResolvedJavaMethod}s that can assign themselves an identifier for use in a side table
+ * mapping methods to {@link InvocationPlugin}s.
+ */
+public interface InvocationPluginIdHolder extends ResolvedJavaMethod {
+    /**
+     * Sets the unique, positive, non-zero identifier for this method.
+     */
+    void setInvocationPluginId(int id);
+
+    /**
+     * Gets the identifier set by {@link #setInvocationPluginId(int)} or 0 if no
+     * {@link InvocationPlugin} identifier was assigned to this method.
+     */
+    int getInvocationPluginId();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,388 @@
+/*
+ * 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.graphbuilderconf;
+
+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.*;
+
+/**
+ * Manages a set of {@link InvocationPlugin}s.
+ */
+public class InvocationPlugins {
+
+    /**
+     * Sentinel class for use with
+     * {@link InvocationPlugins#register(InvocationPlugin, Class, String, Class...)} to denote the
+     * receiver argument for a non-static method.
+     */
+    public static final class Receiver {
+        private Receiver() {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Utility for
+     * {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
+     * registration} of invocation plugins.
+     */
+    public static class Registration {
+
+        private final InvocationPlugins plugins;
+        private final Class<?> declaringClass;
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringClass the class declaring the methods for which plugins will be
+         *            registered via this object
+         */
+        public Registration(InvocationPlugins plugins, Class<?> declaringClass) {
+            this.plugins = plugins;
+            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(plugin, declaringClass, name);
+        }
+
+        /**
+         * 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) {
+            plugins.register(plugin, declaringClass, name, arg);
+        }
+
+        /**
+         * 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) {
+            plugins.register(plugin, declaringClass, name, arg1, arg2);
+        }
+
+        /**
+         * 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) {
+            plugins.register(plugin, declaringClass, name, arg1, arg2, arg3);
+        }
+
+        /**
+         * Registers a plugin for a method with 4 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, declaringClass, name, arg1, arg2, arg3, arg4);
+        }
+
+        /**
+         * Registers a plugin for a method with 5 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register5(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, Class<?> arg5, InvocationPlugin plugin) {
+            plugins.register(plugin, declaringClass, name, arg1, arg2, arg3, arg4, arg5);
+        }
+    }
+
+    static final class MethodInfo {
+        final boolean isStatic;
+        final Class<?> declaringClass;
+        final String name;
+        final Class<?>[] argumentTypes;
+        final InvocationPlugin plugin;
+
+        int id;
+
+        MethodInfo(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+            this.plugin = plugin;
+            this.isStatic = argumentTypes.length == 0 || argumentTypes[0] != Receiver.class;
+            this.declaringClass = declaringClass;
+            this.name = name;
+            this.argumentTypes = argumentTypes;
+            if (!isStatic) {
+                argumentTypes[0] = declaringClass;
+            }
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof MethodInfo) {
+                MethodInfo that = (MethodInfo) obj;
+                boolean res = this.name.equals(that.name) && this.declaringClass.equals(that.declaringClass) && Arrays.equals(this.argumentTypes, that.argumentTypes);
+                assert !res || this.isStatic == that.isStatic;
+                return res;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            // Replay compilation mandates use of stable hash codes
+            return declaringClass.getName().hashCode() ^ name.hashCode();
+        }
+
+        ResolvedJavaMethod resolve(MetaAccessProvider metaAccess) {
+            try {
+                ResolvedJavaMethod method;
+                Class<?>[] parameterTypes = isStatic ? argumentTypes : Arrays.copyOfRange(argumentTypes, 1, argumentTypes.length);
+                if (name.equals("<init>")) {
+                    method = metaAccess.lookupJavaMethod(declaringClass.getDeclaredConstructor(parameterTypes));
+                } else {
+                    method = metaAccess.lookupJavaMethod(declaringClass.getDeclaredMethod(name, parameterTypes));
+                }
+                assert method.isStatic() == isStatic;
+                return method;
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(declaringClass.getName()).append('.').append(name).append('(');
+            for (Class<?> p : argumentTypes) {
+                if (sb.charAt(sb.length() - 1) != '(') {
+                    sb.append(", ");
+                }
+                sb.append(p.getSimpleName());
+            }
+            return sb.append(')').toString();
+        }
+    }
+
+    protected final MetaAccessProvider metaAccess;
+    private final List<MethodInfo> registrations;
+    private final Thread registrationThread;
+
+    /**
+     * The minimum {@linkplain InvocationPluginIdHolder#getInvocationPluginId() id} for a method
+     * associated with a plugin in {@link #plugins}.
+     */
+    private int minId = Integer.MAX_VALUE;
+
+    /**
+     * Resolved methods to plugins map. The keys (i.e., indexes) are derived from
+     * {@link InvocationPluginIdHolder#getInvocationPluginId()}.
+     */
+    private volatile InvocationPlugin[] plugins;
+
+    /**
+     * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
+     * this object.
+     */
+    private InvocationPlugins parent;
+
+    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess, int estimatePluginCount) {
+        this.registrationThread = Thread.currentThread();
+        this.metaAccess = metaAccess;
+        this.registrations = new ArrayList<>(estimatePluginCount);
+        InvocationPlugins p = parent;
+        // Only adopt a non-empty parent
+        while (p != null && p.size() == 0) {
+            p = p.parent;
+        }
+        this.parent = p;
+    }
+
+    private static final int DEFAULT_ESTIMATE_PLUGIN_COUNT = 16;
+
+    /**
+     * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
+     */
+    public InvocationPlugins(InvocationPlugins parent) {
+        this(parent, parent.metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT);
+    }
+
+    public InvocationPlugins(MetaAccessProvider metaAccess) {
+        this(metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT);
+    }
+
+    public InvocationPlugins(MetaAccessProvider metaAccess, int estimatePluginCount) {
+        this(null, metaAccess, estimatePluginCount);
+    }
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+        assert Thread.currentThread() == registrationThread : "invocation plugin registration must be single threaded";
+        MethodInfo methodInfo = new MethodInfo(plugin, declaringClass, name, argumentTypes);
+        assert Checker.check(this, methodInfo, plugin);
+        assert plugins == null : "invocation plugin registration is closed";
+        registrations.add(methodInfo);
+    }
+
+    private static int nextInvocationPluginId = 1;
+
+    /**
+     * 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) {
+        assert method instanceof InvocationPluginIdHolder;
+        if (parent != null) {
+            InvocationPlugin plugin = parent.lookupInvocation(method);
+            if (plugin != null) {
+                return plugin;
+            }
+        }
+        InvocationPluginIdHolder pluggable = (InvocationPluginIdHolder) method;
+        if (plugins == null) {
+            // Must synchronize across all InvocationPlugins objects to ensure thread safe
+            // allocation of InvocationPlugin identifiers
+            synchronized (InvocationPlugins.class) {
+                if (plugins == null) {
+                    if (registrations.isEmpty()) {
+                        plugins = new InvocationPlugin[0];
+                    } else {
+                        int max = Integer.MIN_VALUE;
+                        for (MethodInfo methodInfo : registrations) {
+                            InvocationPluginIdHolder p = (InvocationPluginIdHolder) methodInfo.resolve(metaAccess);
+                            int id = p.getInvocationPluginId();
+                            if (id == 0) {
+                                id = nextInvocationPluginId++;
+                                p.setInvocationPluginId(id);
+                            }
+                            if (id < minId) {
+                                minId = id;
+                            }
+                            if (id > max) {
+                                max = id;
+
+                            }
+                            methodInfo.id = id;
+                        }
+
+                        int length = (max - minId) + 1;
+                        plugins = new InvocationPlugin[length];
+                        for (MethodInfo m : registrations) {
+                            int index = m.id - minId;
+                            plugins[index] = m.plugin;
+                        }
+                    }
+                }
+            }
+        }
+
+        int id = pluggable.getInvocationPluginId();
+        int index = id - minId;
+        return index >= 0 && index < plugins.length ? plugins[index] : null;
+    }
+
+    /**
+     * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
+     * before searching in this object.
+     */
+    public InvocationPlugins getParent() {
+        return parent;
+    }
+
+    @Override
+    public String toString() {
+        return registrations.stream().map(MethodInfo::toString).collect(Collectors.joining(", ")) + " / parent: " + this.parent;
+    }
+
+    private static class Checker {
+        private static final int MAX_ARITY = 5;
+        /**
+         * The set of all {@link InvocationPlugin#apply} method signatures.
+         */
+        static final Class<?>[][] SIGS;
+        static {
+            ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
+            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
+                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
+                    Class<?>[] sig = method.getParameterTypes();
+                    assert sig[0] == GraphBuilderContext.class;
+                    assert sig[1] == ResolvedJavaMethod.class;
+                    assert Arrays.asList(Arrays.copyOfRange(sig, 2, sig.length)).stream().allMatch(c -> c == ValueNode.class);
+                    while (sigs.size() < sig.length - 1) {
+                        sigs.add(null);
+                    }
+                    sigs.set(sig.length - 2, sig);
+                }
+            }
+            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
+                            ValueNode.class.getSimpleName());
+            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
+        }
+
+        public static boolean check(InvocationPlugins plugins, MethodInfo method, InvocationPlugin plugin) {
+            InvocationPlugins p = plugins;
+            while (p != null) {
+                assert !p.registrations.contains(method) : "a plugin is already registered for " + method;
+                p = p.parent;
+            }
+            int arguments = method.argumentTypes.length;
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
+                        return true;
+                    }
+                }
+            }
+            throw new AssertionError(format("graph builder plugin for %s not found", method));
+        }
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public int size() {
+        return registrations.size();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+public interface LoadFieldPlugin extends GraphBuilderPlugin {
+    @SuppressWarnings("unused")
+    default boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
+        return false;
+    }
+
+    @SuppressWarnings("unused")
+    default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) {
+        return false;
+    }
+
+    default boolean tryConstantFold(GraphBuilderContext b, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant receiver) {
+        JavaConstant result = constantReflection.readConstantFieldValue(field, receiver);
+        if (result != null) {
+            ConstantNode constantNode = b.append(ConstantNode.forConstant(result, metaAccess));
+            b.push(constantNode.getKind().getStackKind(), constantNode);
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadIndexedPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+public interface LoadIndexedPlugin extends GraphBuilderPlugin {
+    @SuppressWarnings("unused")
+    default boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) {
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoopExplosionPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+
+public interface LoopExplosionPlugin extends GraphBuilderPlugin {
+    boolean shouldExplodeLoops(ResolvedJavaMethod method);
+
+    boolean shouldMergeExplosions(ResolvedJavaMethod method);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ParameterPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,30 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.calc.*;
+
+public interface ParameterPlugin extends GraphBuilderPlugin {
+    FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp);
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Mar 17 11:23:06 2015 -0700
@@ -31,9 +31,10 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.phases.util.*;
 
 @ServiceProvider(HotSpotBackendFactory.class)
@@ -124,9 +125,11 @@
         HotSpotMetaAccessProvider metaAccess;
         HotSpotLoweringProvider lowerer;
         HotSpotSnippetReflectionProvider snippetReflection;
-        Replacements replacements;
+        HotSpotReplacementsImpl replacements;
         HotSpotDisassemblerProvider disassembler;
         HotSpotSuitesProvider suites;
+        HotSpotWordTypes wordTypes;
+        Plugins plugins;
         try (InitTimer t = timer("create providers")) {
             try (InitTimer rt = timer("create HotSpotRegisters provider")) {
                 registers = createRegisters();
@@ -152,7 +155,8 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
             }
-            Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, new HotSpotStampProvider());
+            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
 
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(runtime);
@@ -163,10 +167,17 @@
             try (InitTimer rt = timer("create Disassembler provider")) {
                 disassembler = createDisassembler(runtime);
             }
+            try (InitTimer rt = timer("create WordTypes")) {
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordKind);
+            }
+            try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
+                plugins = HotSpotGraphBuilderPlugins.create(runtime.getConfig(), wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements, target.arch);
+                replacements.setGraphBuilderPlugins(plugins);
+            }
             try (InitTimer rt = timer("create Suites provider")) {
-                suites = createSuites(runtime);
+                suites = createSuites(runtime, plugins);
             }
-            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection, wordTypes, plugins);
         }
         try (InitTimer rt = timer("instantiate backend")) {
             return createBackend(runtime, providers);
@@ -185,7 +196,7 @@
         return new HotSpotDisassemblerProvider(runtime);
     }
 
-    protected Replacements createReplacements(HotSpotGraalRuntimeProvider runtime, Providers p, SnippetReflectionProvider snippetReflection) {
+    protected HotSpotReplacementsImpl createReplacements(HotSpotGraalRuntimeProvider runtime, Providers p, SnippetReflectionProvider snippetReflection) {
         return new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), p.getCodeCache().getTarget());
     }
 
@@ -210,8 +221,8 @@
         return new HotSpotMetaAccessProvider(runtime);
     }
 
-    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime) {
-        return new HotSpotSuitesProvider(runtime);
+    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime, Plugins plugins) {
+        return new HotSpotSuitesProvider(runtime, plugins);
     }
 
     protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime) {
@@ -249,15 +260,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             *
+             * 
              * Draft Version 0.96
-             *
+             * 
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             *
+             * 
              * 3.2.1
-             *
+             * 
              * ...
-             *
+             * 
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,85 @@
+/*
+ * 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.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("BenchMarkCounter")
+public class AMD64HotSpotCounterOp extends HotSpotCounterOp {
+    public static final LIRInstructionClass<AMD64HotSpotCounterOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCounterOp.class);
+
+    @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private StackSlotValue backupSlot;
+
+    public AMD64HotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config, StackSlotValue backupSlot) {
+        super(TYPE, name, group, increment, registers, config);
+        this.backupSlot = backupSlot;
+    }
+
+    public AMD64HotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config, StackSlotValue backupSlot) {
+        super(TYPE, names, groups, increments, registers, config);
+        this.backupSlot = backupSlot;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        AMD64MacroAssembler masm = (AMD64MacroAssembler) crb.asm;
+        TargetDescription target = crb.target;
+
+        Register scratch = rax;
+
+        // address for counters array
+        AMD64Address countersArrayAddr = new AMD64Address(thread, config.graalCountersThreadOffset);
+        Register countersArrayReg = scratch;
+
+        // backup scratch register
+        masm.movq((AMD64Address) crb.asAddress(backupSlot), scratch);
+
+        // load counters array
+        masm.movptr(countersArrayReg, countersArrayAddr);
+
+        forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+
+        // restore scratch register
+        masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot));
+    }
+
+    private void emitIncrement(AMD64MacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) {
+        // address for counter value
+        AMD64Address counterAddr = new AMD64Address(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment)));
+        // increment counter (in memory)
+        if (isConstant(increment)) {
+            masm.incrementl(counterAddr, asInt(asConstant(increment)));
+        } else {
+            masm.addq(counterAddr, asRegister(increment));
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Mar 17 11:23:06 2015 -0700
@@ -39,9 +39,11 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.HotSpotStoreConstantOp;
+import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
@@ -54,6 +56,8 @@
 import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
 
 /**
@@ -118,6 +122,41 @@
 
     SaveRbp saveRbp;
 
+    private static final class RescueSlotDummyOp extends LIRInstruction {
+        public static final LIRInstructionClass<RescueSlotDummyOp> TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class);
+
+        @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private StackSlotValue slot;
+
+        public RescueSlotDummyOp(FrameMapBuilder frameMapBuilder, LIRKind kind) {
+            super(TYPE);
+            slot = frameMapBuilder.allocateSpillSlot(kind);
+        }
+
+        public StackSlotValue getSlot() {
+            return slot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+        }
+    }
+
+    private RescueSlotDummyOp rescueSlotOp;
+
+    private StackSlotValue getOrInitRescueSlot() {
+        if (rescueSlotOp == null) {
+            // create dummy instruction to keep the rescue slot alive
+            rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind());
+            // insert dummy instruction into the start block
+            LIR lir = getResult().getLIR();
+            List<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
+            // Note: we do not insert at position 1 to avoid interference with the save rpb op
+            instructions.add(instructions.size() - 1, rescueSlotOp);
+            Debug.dump(lir, "created rescue dummy op");
+        }
+        return rescueSlotOp.getSlot();
+    }
+
     /**
      * List of epilogue operations that need to restore RBP.
      */
@@ -440,6 +479,10 @@
         for (AMD64HotSpotEpilogueOp op : epilogueOps) {
             op.savedRbp = savedRbp;
         }
+        if (BenchmarkCounters.enabled) {
+            // ensure that the rescue slot is available
+            getOrInitRescueSlot();
+        }
     }
 
     private static LIRKind toStackKind(LIRKind kind) {
@@ -626,4 +669,20 @@
             return super.canInlineConstant(c);
         }
     }
+
+    @Override
+    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
+        if (BenchmarkCounters.enabled) {
+            return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot());
+        }
+        return null;
+    }
+
+    @Override
+    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
+        if (BenchmarkCounters.enabled) {
+            return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot());
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Mar 17 11:23:06 2015 -0700
@@ -27,8 +27,10 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.sparc.*;
@@ -60,18 +62,23 @@
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
-        Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, new HotSpotStampProvider());
+        HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+        Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
-        HotSpotSuitesProvider suites = createSuites(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordKind);
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(runtime.getConfig(), wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements, target.arch);
+        replacements.setGraphBuilderPlugins(plugins);
+        HotSpotSuitesProvider suites = createSuites(runtime, plugins);
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
+                        wordTypes, plugins);
 
         return createBackend(runtime, providers);
     }
 
-    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime) {
-        return new HotSpotSuitesProvider(runtime);
+    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime, Plugins plugins) {
+        return new HotSpotSuitesProvider(runtime, plugins);
     }
 
     protected HotSpotCodeCacheProvider createCodeCache(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,84 @@
+/*
+ * 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.hotspot.sparc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("BenchMarkCounter")
+public class SPARCHotSpotCounterOp extends HotSpotCounterOp {
+    public static final LIRInstructionClass<SPARCHotSpotCounterOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class);
+
+    @Temp({OperandFlag.REG}) private AllocatableValue scratch0;
+    @Temp({OperandFlag.REG}) private AllocatableValue scratch1;
+
+    public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue scratch0, AllocatableValue scratch1) {
+        super(TYPE, name, group, increment, registers, config);
+        this.scratch0 = scratch0;
+        this.scratch1 = scratch1;
+    }
+
+    public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue scratch0, AllocatableValue scratch1) {
+        super(TYPE, names, groups, increments, registers, config);
+        this.scratch0 = scratch0;
+        this.scratch1 = scratch1;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+        TargetDescription target = crb.target;
+
+        // address for counters array
+        SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.graalCountersThreadOffset);
+        Register countersArrayReg = asRegister(scratch0);
+
+        // load counters array
+        masm.ldx(countersArrayAddr, countersArrayReg);
+
+        forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+    }
+
+    private void emitIncrement(SPARCMacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) {
+        // address for counter
+        SPARCAddress counterAddr = new SPARCAddress(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment)));
+        Register counterReg = asRegister(scratch1);
+        // load counter value
+        masm.ldx(counterAddr, counterReg);
+        // increment counter
+        if (isConstant(increment)) {
+            masm.add(counterReg, asInt(asConstant(increment)), counterReg);
+        } else {
+            masm.add(counterReg, asRegister(increment), counterReg);
+        }
+        // store counter value
+        masm.stx(counterReg, counterAddr);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Mar 17 11:23:06 2015 -0700
@@ -37,6 +37,7 @@
 import com.oracle.graal.compiler.sparc.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
@@ -48,6 +49,7 @@
 import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
+import com.oracle.graal.sparc.*;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
 
@@ -362,4 +364,32 @@
         assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!";
         append(new NullCheckOp(load(address), state));
     }
+
+    @Override
+    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
+        if (BenchmarkCounters.enabled) {
+            try (SPARCScratchRegister sc0 = SPARCScratchRegister.get()) {
+                RegisterValue scratch0 = sc0.getRegister().asValue(getLIRKindTool().getWordKind());
+                try (SPARCScratchRegister sc1 = SPARCScratchRegister.get()) {
+                    RegisterValue scratch1 = sc1.getRegister().asValue(getLIRKindTool().getWordKind());
+                    return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, scratch0, scratch1);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
+        if (BenchmarkCounters.enabled) {
+            try (SPARCScratchRegister sc0 = SPARCScratchRegister.get()) {
+                RegisterValue scratch0 = sc0.getRegister().asValue(getLIRKindTool().getWordKind());
+                try (SPARCScratchRegister sc1 = SPARCScratchRegister.get()) {
+                    RegisterValue scratch1 = sc1.getRegister().asValue(getLIRKindTool().getWordKind());
+                    return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, scratch0, scratch1);
+                }
+            }
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -251,7 +251,7 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
             HighTierContext highContext = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
-            new NodeIntrinsificationPhase(getProviders(), getSnippetReflection()).apply(graph);
+            new NodeIntrinsificationPhase(getMetaAccess(), getConstantReflection(), getSnippetReflection(), getProviders().getForeignCalls(), getProviders().getStampProvider()).apply(graph);
             new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
             new CanonicalizerPhase().apply(graph, highContext);
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,112 @@
+/*
+ * 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.hotspot;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.debug.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+
+public abstract class HotSpotCounterOp extends LIRInstruction {
+    public static final LIRInstructionClass<HotSpotCounterOp> TYPE = LIRInstructionClass.create(HotSpotCounterOp.class);
+
+    private final String[] names;
+    private final String[] groups;
+    protected final Register thread;
+    protected final HotSpotVMConfig config;
+    @Alive({OperandFlag.CONST, OperandFlag.REG}) protected Value[] increments;
+
+    public HotSpotCounterOp(LIRInstructionClass<? extends HotSpotCounterOp> c, String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
+        this(c, new String[]{name}, new String[]{group}, new Value[]{increment}, registers, config);
+    }
+
+    public HotSpotCounterOp(LIRInstructionClass<? extends HotSpotCounterOp> c, String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
+        super(c);
+
+        assert names.length == groups.length;
+        assert groups.length == increments.length;
+
+        this.names = names;
+        this.groups = groups;
+        this.increments = increments;
+        this.thread = registers.getThreadRegister();
+        this.config = config;
+    }
+
+    protected static int getDisplacementForLongIndex(TargetDescription target, long index) {
+        long finalDisp = index * target.getSizeInBytes(Kind.Long);
+        if (!NumUtil.isInt(finalDisp)) {
+            throw GraalInternalError.unimplemented("cannot deal with indices that big: " + index);
+        }
+        return (int) finalDisp;
+    }
+
+    protected interface CounterProcedure {
+        void apply(String name, String group, Value increment);
+    }
+
+    protected void forEachCounter(CounterProcedure proc) {
+        for (int i = 0; i < names.length; i++) {
+            proc.apply(names[i], groups[i], increments[i]);
+        }
+    }
+
+    protected int getIndex(String name, String group, Value increment) {
+        if (isConstant(increment)) {
+            // get index for the counter
+            return BenchmarkCounters.getIndexConstantIncrement(name, group, config, asLong(asConstant(increment)));
+        }
+        assert isRegister(increment) : "Unexpected Value: " + increment;
+        // get index for the counter
+        return BenchmarkCounters.getIndex(name, group, config);
+    }
+
+    private static long asLong(JavaConstant value) {
+        Kind kind = value.getKind();
+        switch (kind) {
+            case Byte:
+            case Short:
+            case Char:
+            case Int:
+                return value.asInt();
+            case Long:
+                return value.asLong();
+            default:
+                throw new IllegalArgumentException("not an integer kind: " + kind);
+        }
+    }
+
+    protected static int asInt(JavaConstant value) {
+        long l = asLong(value);
+        if (!NumUtil.isInt(l)) {
+            throw GraalInternalError.shouldNotReachHere("value does not fit into int: " + l);
+        }
+        return (int) l;
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Mar 17 11:23:06 2015 -0700
@@ -31,8 +31,6 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -72,14 +70,6 @@
         final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
         HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
 
-        try (InitTimer st = timer("graphBuilderPlugins.initialize")) {
-            Plugins plugins = HotSpotGraphBuilderPlugins.create(config, providers);
-            providers.setGraphBuilderPlugins(plugins);
-            GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-            phase.getGraphBuilderConfig().setPlugins(plugins);
-            replacements.completeInitialization(plugins);
-        }
-
         try (InitTimer st = timer("foreignCalls.initialize")) {
             foreignCalls.initialize(providers, config);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Mar 17 11:23:06 2015 -0700
@@ -27,26 +27,13 @@
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
 
-import sun.misc.*;
-
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.replacements.nodes.*;
 
 import edu.umd.cs.findbugs.annotations.*;
 
@@ -105,59 +92,62 @@
 
     public static boolean enabled = false;
 
-    public static final ConcurrentHashMap<String, Integer> indexes = new ConcurrentHashMap<>();
-    public static final ArrayList<String> groups = new ArrayList<>();
+    private static class Counter {
+        public final int index;
+        public final String group;
+        public final AtomicLong staticCounters;
+
+        public Counter(int index, String group, AtomicLong staticCounters) {
+            this.index = index;
+            this.group = group;
+            this.staticCounters = staticCounters;
+        }
+    }
+
+    public static final ConcurrentHashMap<String, Counter> counterMap = new ConcurrentHashMap<>();
     public static long[] delta;
-    public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
+
+    public static int getIndexConstantIncrement(String name, String group, HotSpotVMConfig config, long increment) {
+        Counter counter = getCounter(name, group, config);
+        counter.staticCounters.addAndGet(increment);
+        return counter.index;
+    }
+
+    public static int getIndex(String name, String group, HotSpotVMConfig config) {
+        Counter counter = getCounter(name, group, config);
+        return counter.index;
+    }
 
     @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
-    private static int getIndex(DynamicCounterNode counter, StructuredGraph currentGraph) {
+    private static Counter getCounter(String name, String group, HotSpotVMConfig config) throws GraalInternalError {
         if (!enabled) {
-            throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
+            throw new GraalInternalError("cannot access count index when counters are not enabled: " + group + ", " + name);
         }
-        String name;
-        String group = counter.getGroup();
-        if (counter.isWithContext()) {
-            name = counter.getName() + " @ ";
-            if (currentGraph.method() != null) {
-                StackTraceElement stackTraceElement = currentGraph.method().asStackTraceElement(0);
-                if (stackTraceElement != null) {
-                    name += " " + stackTraceElement.toString();
-                } else {
-                    name += currentGraph.method().format("%h.%n");
-                }
-            }
-            if (currentGraph.name != null) {
-                name += " (" + currentGraph.name + ")";
-            }
-            name += "#" + group;
-
-        } else {
-            name = counter.getName() + "#" + group;
-        }
-        Integer index = indexes.get(name);
-        if (index == null) {
+        String nameGroup = name + "#" + group;
+        Counter counter = counterMap.get(nameGroup);
+        if (counter == null) {
             synchronized (BenchmarkCounters.class) {
-                index = indexes.get(name);
-                if (index == null) {
-                    index = indexes.size();
-                    indexes.put(name, index);
-                    groups.add(group);
-                    staticCounters.add(new AtomicLong());
+                counter = counterMap.get(nameGroup);
+                if (counter == null) {
+                    counter = new Counter(counterMap.size(), group, new AtomicLong());
+                    counterMap.put(nameGroup, counter);
                 }
             }
         }
-        assert groups.get(index).equals(group) : "mismatching groups: " + groups.get(index) + " vs. " + group;
-        if (counter.getIncrement().isConstant()) {
-            staticCounters.get(index).addAndGet(counter.getIncrement().asJavaConstant().asLong());
+        assert counter.group.equals(group) : "mismatching groups: " + counter.group + " vs. " + group;
+        int countersSize = config.graalCountersSize;
+        if (counter.index >= countersSize) {
+            throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + countersSize + ")");
         }
-        return index;
+        return counter;
     }
 
     private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
-        if (!groups.isEmpty()) {
-            out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
-            for (String group : new TreeSet<>(groups)) {
+        if (!counterMap.isEmpty()) {
+            out.println("====== dynamic counters (" + counterMap.size() + " in total) ======");
+            TreeSet<String> set = new TreeSet<>();
+            counterMap.forEach((nameGroup, counter) -> set.add(counter.group));
+            for (String group : set) {
                 if (group != null) {
                     if (DUMP_STATIC) {
                         dumpCounters(out, seconds, counters, true, group, maxRows);
@@ -181,9 +171,9 @@
         // collect the numbers
         long[] array;
         if (staticCounter) {
-            array = new long[indexes.size()];
-            for (int i = 0; i < array.length; i++) {
-                array[i] = staticCounters.get(i).get();
+            array = new long[counterMap.size()];
+            for (Counter counter : counterMap.values()) {
+                array[counter.index] = counter.staticCounters.get();
             }
         } else {
             array = counters.clone();
@@ -193,9 +183,10 @@
         }
         // sort the counters by putting them into a sorted map
         long sum = 0;
-        for (Map.Entry<String, Integer> entry : indexes.entrySet()) {
-            int index = entry.getValue();
-            if (groups.get(index).equals(group)) {
+        for (Map.Entry<String, Counter> entry : counterMap.entrySet()) {
+            Counter counter = entry.getValue();
+            int index = counter.index;
+            if (counter.group.equals(group)) {
                 sum += array[index];
                 sorted.put(array[index] * array.length + index, entry.getKey().substring(0, entry.getKey().length() - group.length() - 1));
             }
@@ -383,51 +374,4 @@
             dump(TTY.cachedOut, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters(), 100);
         }
     }
-
-    private static final LocationIdentity COUNTER_ARRAY_LOCATION = NamedLocationIdentity.mutable("COUNTER_ARRAY_LOCATION");
-    private static final LocationIdentity COUNTER_LOCATION = NamedLocationIdentity.mutable("COUNTER_LOCATION");
-
-    @NodeInfo(nameTemplate = "CounterIndex")
-    private static final class CounterIndexNode extends FloatingNode implements LIRLowerable {
-
-        public static final NodeClass<CounterIndexNode> TYPE = NodeClass.create(CounterIndexNode.class);
-        protected final Object counter;
-        protected final int countersSize;
-
-        protected CounterIndexNode(Stamp stamp, DynamicCounterNode counter, int countersSize) {
-            super(TYPE, stamp);
-            this.countersSize = countersSize;
-            this.counter = counter;
-        }
-
-        @Override
-        public void generate(NodeLIRBuilderTool generator) {
-            int index = BenchmarkCounters.getIndex((DynamicCounterNode) counter, graph());
-            if (index >= countersSize) {
-                throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + countersSize + ")");
-            }
-
-            generator.setResult(this, JavaConstant.forIntegerKind(getKind(), index));
-        }
-    }
-
-    public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) {
-        StructuredGraph graph = counter.graph();
-
-        ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
-
-        CounterIndexNode index = graph.unique(new CounterIndexNode(StampFactory.forKind(wordKind), counter, config.graalCountersSize));
-        ConstantLocationNode arrayLocation = graph.unique(new ConstantLocationNode(COUNTER_ARRAY_LOCATION, config.graalCountersThreadOffset));
-        ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE));
-        IndexedLocationNode location = graph.unique(new IndexedLocationNode(COUNTER_LOCATION, 0, index, Unsafe.ARRAY_LONG_INDEX_SCALE));
-        ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE));
-        AddNode add = graph.unique(new AddNode(read, counter.getIncrement()));
-        WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE));
-
-        graph.addBeforeFixed(counter, thread);
-        graph.addBeforeFixed(counter, readArray);
-        graph.addBeforeFixed(counter, read);
-        graph.addBeforeFixed(counter, write);
-        graph.removeFixed(counter);
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Mar 17 11:23:06 2015 -0700
@@ -36,7 +36,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.*;
@@ -105,8 +104,6 @@
             lowerStoreHubNode((StoreHubNode) n, graph);
         } else if (n instanceof OSRStartNode) {
             lowerOSRStartNode((OSRStartNode) n);
-        } else if (n instanceof DynamicCounterNode) {
-            lowerDynamicCounterNode((DynamicCounterNode) n);
         } else if (n instanceof BytecodeExceptionNode) {
             lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
         } else if (n instanceof CheckCastDynamicNode) {
@@ -369,13 +366,6 @@
         }
     }
 
-    private void lowerDynamicCounterNode(DynamicCounterNode n) {
-        StructuredGraph graph = n.graph();
-        if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
-            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
-        }
-    }
-
     static final class Exceptions {
         protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
         protected static final NullPointerException cachedNullPointerException;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Mar 17 11:23:06 2015 -0700
@@ -22,21 +22,20 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.java.GraphBuilderContext.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.java.InvocationPlugins.Registration;
-import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
@@ -50,36 +49,45 @@
  */
 public class HotSpotGraphBuilderPlugins {
 
+    private static final int PLUGIN_COUNT_ESTIMATE = 160;
+
     /**
      * Creates a {@link Plugins} object that should be used when running on HotSpot.
+     *
+     * @param constantReflection
+     * @param snippetReflection
+     * @param foreignCalls
+     * @param stampProvider
      */
-    public static Plugins create(HotSpotVMConfig config, HotSpotProviders providers) {
+    public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
+                    SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements, Architecture arch) {
 
-        MetaAccessProvider metaAccess = providers.getMetaAccess();
-        HotSpotWordTypes wordTypes = providers.getWordTypes();
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, PLUGIN_COUNT_ESTIMATE);
 
         Plugins plugins = new Plugins(invocationPlugins);
-        NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(providers, providers.getSnippetReflection());
-        ConstantReflectionProvider constantReflection = providers.getConstantReflection();
-        HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(providers.getSnippetReflection(), wordTypes);
+        NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
+        HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
 
         plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes));
         plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection));
         plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes));
-        plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, (ReplacementsImpl) providers.getReplacements()));
+        plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, replacements));
         plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(nodeIntrinsification, wordOperationPlugin));
 
-        registerObjectPlugins(invocationPlugins, metaAccess);
-        registerSystemPlugins(invocationPlugins, metaAccess, providers.getForeignCalls());
+        registerObjectPlugins(invocationPlugins);
+        registerSystemPlugins(invocationPlugins, foreignCalls);
         registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
-        registerStableOptionPlugins(invocationPlugins, metaAccess);
-        StandardGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), providers.getCodeCache().target.arch, invocationPlugins, !config.useHeapProfiler);
+        registerStableOptionPlugins(invocationPlugins);
+        StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, arch, invocationPlugins, !config.useHeapProfiler);
+
+        int size = invocationPlugins.size();
+        assert PLUGIN_COUNT_ESTIMATE >= size : String.format("adjust %s.PLUGIN_COUNT_ESTIMATE to be above or equal to %d", HotSpotGraphBuilderPlugins.class.getSimpleName(), size);
+        assert PLUGIN_COUNT_ESTIMATE - size < 20 : String.format("adjust %s.PLUGIN_COUNT_ESTIMATE to be closer to %d", HotSpotGraphBuilderPlugins.class.getSimpleName(), size);
         return plugins;
     }
 
-    private static void registerObjectPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
-        Registration r = new Registration(plugins, metaAccess, Object.class);
+    private static void registerObjectPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Object.class);
         r.register1("getClass", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
                 ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
@@ -97,8 +105,8 @@
         });
     }
 
-    private static void registerSystemPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
-        Registration r = new Registration(plugins, metaAccess, System.class);
+    private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
+        Registration r = new Registration(plugins, System.class);
         r.register0("currentTimeMillis", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
                 ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long));
@@ -118,7 +126,7 @@
     }
 
     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, HotSpotVMConfig config) {
-        Registration r = new Registration(plugins, metaAccess, Thread.class);
+        Registration r = new Registration(plugins, Thread.class);
         r.register0("currentThread", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
                 CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind()));
@@ -133,8 +141,8 @@
         });
     }
 
-    private static void registerStableOptionPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
-        Registration r = new Registration(plugins, metaAccess, StableOptionValue.class);
+    private static void registerStableOptionPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, StableOptionValue.class);
         r.register1("getValue", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
                 if (rcvr.isConstant() && !rcvr.isNullConstant()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -28,10 +28,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderContext.Replacement;
-import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.word.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Tue Mar 17 11:23:06 2015 -0700
@@ -23,40 +23,38 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.*;
-import com.oracle.graal.replacements.StandardGraphBuilderPlugins.*;
+import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
 
 /**
  * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration.
  */
 final class HotSpotInvocationPlugins extends InvocationPlugins {
     final HotSpotVMConfig config;
-    final MetaAccessProvider metaAccess;
 
-    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, int estimatePluginCount) {
+        super(metaAccess, estimatePluginCount);
         this.config = config;
-        this.metaAccess = metaAccess;
     }
 
     @Override
-    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
+    public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
         if (!config.usePopCountInstruction) {
-            if (method.getName().equals("bitCount")) {
-                assert method.getDeclaringClass().equals(metaAccess.lookupJavaType(Integer.class)) || method.getDeclaringClass().equals(metaAccess.lookupJavaType(Long.class));
+            if (name.equals("bitCount")) {
+                assert declaringClass.equals(Integer.class) || declaringClass.equals(Long.class);
                 return;
             }
         }
         if (!config.useCountLeadingZerosInstruction) {
-            if (method.getName().equals("numberOfLeadingZeros")) {
-                assert method.getDeclaringClass().equals(metaAccess.lookupJavaType(Integer.class)) || method.getDeclaringClass().equals(metaAccess.lookupJavaType(Long.class));
+            if (name.equals("numberOfLeadingZeros")) {
+                assert declaringClass.equals(Integer.class) || declaringClass.equals(Long.class);
                 return;
             }
         }
         if (!config.useCountTrailingZerosInstruction) {
-            if (method.getName().equals("numberOfTrailingZeros")) {
-                assert method.getDeclaringClass().equals(metaAccess.lookupJavaType(Integer.class));
+            if (name.equals("numberOfTrailingZeros")) {
+                assert declaringClass.equals(Integer.class);
                 return;
             }
         }
@@ -67,6 +65,6 @@
                 return;
             }
         }
-        super.register(method, plugin);
+        super.register(plugin, declaringClass, name, argumentTypes);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -27,8 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 
 public final class HotSpotLoadFieldPlugin implements LoadFieldPlugin {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -24,11 +24,10 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -24,8 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Tue Mar 17 11:23:06 2015 -0700
@@ -24,8 +24,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
@@ -41,17 +41,18 @@
     private final HotSpotRegistersProvider registers;
     private final SnippetReflectionProvider snippetReflection;
     private final HotSpotWordTypes wordTypes;
-    private Plugins graphBuilderPlugins;
+    private final Plugins graphBuilderPlugins;
 
     public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls,
                     LoweringProvider lowerer, Replacements replacements, HotSpotDisassemblerProvider disassembler, SuitesProvider suites, HotSpotRegistersProvider registers,
-                    SnippetReflectionProvider snippetReflection) {
+                    SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins) {
         super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, new HotSpotStampProvider());
         this.disassembler = disassembler;
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
-        this.wordTypes = new HotSpotWordTypes(metaAccess, codeCache.getTarget().wordKind);
+        this.wordTypes = wordTypes;
+        this.graphBuilderPlugins = graphBuilderPlugins;
     }
 
     @Override
@@ -80,12 +81,7 @@
         return snippetReflection;
     }
 
-    public void setGraphBuilderPlugins(Plugins plugins) {
-        graphBuilderPlugins = plugins;
-    }
-
     public Plugins getGraphBuilderPlugins() {
-        assert graphBuilderPlugins != null;
         return graphBuilderPlugins;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Tue Mar 17 11:23:06 2015 -0700
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.nodes.*;
@@ -41,7 +42,7 @@
 /**
  * Implementation of {@link JavaMethod} for resolved HotSpot methods.
  */
-public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified {
+public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, InvocationPluginIdHolder {
 
     private static final long serialVersionUID = -5486975070147586588L;
 
@@ -740,4 +741,15 @@
         }
         return runtime().getCompilerToVM().hasCompiledCodeForOSR(metaspaceMethod, entryBCI, level);
     }
+
+    private int invocationPluginId;
+
+    public void setInvocationPluginId(int id) {
+        assert invocationPluginId == 0;
+        invocationPluginId = id;
+    }
+
+    public int getInvocationPluginId() {
+        return invocationPluginId;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Mar 17 11:23:06 2015 -0700
@@ -24,11 +24,12 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.DebugInfoMode;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
@@ -65,9 +66,9 @@
 
     }
 
-    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime) {
+    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime, Plugins plugins) {
         this.runtime = runtime;
-        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite(plugins);
         this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
         this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
@@ -99,9 +100,9 @@
         return ret;
     }
 
-    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite(Plugins plugins) {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins);
         suite.appendPhase(new GraphBuilderPhase(config));
         return suite;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -30,10 +30,10 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
@@ -57,14 +56,6 @@
         gen.setResult(this, rawThread.asValue(wordKind));
     }
 
-    private static int eetopOffset() {
-        try {
-            return (int) UnsafeAccess.unsafe.objectFieldOffset(Thread.class.getDeclaredField("eetop"));
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
     @NodeIntrinsic
     public static native Word get();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -180,24 +180,26 @@
             maybeCastArgument(receiverSkip + index, parameterType);
         }
 
+        if (target.canBeStaticallyBound()) {
+            return createTargetInvokeNode(target, intrinsicMethod);
+        }
+
         // Try to get the most accurate receiver type
         if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
             ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
             if (receiverType != null) {
                 AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
                 if (concreteMethod != null) {
+                    graph().getAssumptions().record(concreteMethod);
                     return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
                 }
             }
-        }
-
-        if (target.canBeStaticallyBound()) {
-            return createTargetInvokeNode(target, intrinsicMethod);
-        }
-
-        AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
-        if (concreteMethod != null) {
-            return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
+        } else {
+            AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
+            if (concreteMethod != null) {
+                graph().getAssumptions().record(concreteMethod);
+                return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
+            }
         }
 
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Mar 17 11:23:06 2015 -0700
@@ -157,7 +157,8 @@
     public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 
     @Snippet
-    public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) {
+    public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
+                    @SuppressWarnings("unused") @ConstantParameter String typeContext) {
         KlassPointer hub = ClassGetHubNode.readClass(type);
         if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
             if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) {
@@ -170,7 +171,11 @@
                  */
                 if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) {
                     Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-                    return allocateInstance(layoutHelper, hub, prototypeMarkWord, fillContents, threadRegister, false, typeContext);
+                    /*
+                     * FIXME(je,ds): we should actually pass typeContext instead of "" but late
+                     * binding of parameters is not yet supported by the GraphBuilderPlugin system.
+                     */
+                    return allocateInstance(layoutHelper, hub, prototypeMarkWord, fillContents, threadRegister, false, "");
                 }
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue Mar 17 11:23:06 2015 -0700
@@ -28,10 +28,11 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -79,11 +80,11 @@
 
     @Override
     protected StructuredGraph getGraph() {
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
         Plugins defaultPlugins = providers.getGraphBuilderPlugins();
-        Plugins plugins = config.getPlugins().updateFrom(defaultPlugins, false);
-        plugins.getInvocationPlugins().setDefaults(defaultPlugins.getInvocationPlugins());
-        plugins.setParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), plugins.getParameterPlugin(), providers.getMetaAccess(), providers.getSnippetReflection()));
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        Plugins plugins = new Plugins(defaultPlugins);
+        plugins.setParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), plugins.getParameterPlugin(), metaAccess, providers.getSnippetReflection()));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
 
         // Stubs cannot have optimistic assumptions since they have
         // to be valid for the entire run of the VM. Nor can they be
@@ -93,7 +94,7 @@
 
         assert SnippetGraphUnderConstruction.get() == null;
         SnippetGraphUnderConstruction.set(graph);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph);
         SnippetGraphUnderConstruction.set(null);
 
         graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Mar 17 11:23:06 2015 -0700
@@ -40,6 +40,8 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import com.oracle.graal.lir.profiling.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.schedule.*;
@@ -180,7 +182,7 @@
                     Suites suites = new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier());
                     SchedulePhase schedule = emitFrontEnd(providers, target, graph, null, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph),
                                     null, suites);
-                    LIRSuites lirSuites = providers.getSuites().getDefaultLIRSuites();
+                    LIRSuites lirSuites = createLIRSuites();
                     emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, schedule, getRegisterConfig(), lirSuites);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
@@ -210,6 +212,15 @@
         return code;
     }
 
+    private LIRSuites createLIRSuites() {
+        LIRSuites lirSuites = new LIRSuites(providers.getSuites().getDefaultLIRSuites());
+        ListIterator<LIRPhase<PostAllocationOptimizationContext>> moveProfiling = lirSuites.getPostAllocationOptimizationStage().findPhase(MoveProfiling.class);
+        if (moveProfiling != null) {
+            moveProfiling.remove();
+        }
+        return lirSuites;
+    }
+
     /**
      * Gets the compilation result for this stub, compiling it first if necessary, and installing it
      * in code.
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Mar 17 11:23:06 2015 -0700
@@ -37,11 +37,10 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Mar 17 11:23:06 2015 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.java;
 
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
@@ -54,8 +56,8 @@
 
     }
 
-    public DefaultSuitesProvider() {
-        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
+    public DefaultSuitesProvider(Plugins plugins) {
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite(plugins);
         this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
         this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
@@ -72,9 +74,9 @@
         return defaultGraphBuilderSuite;
     }
 
-    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite(Plugins plugins) {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
-        suite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault()));
+        suite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(plugins)));
         return suite;
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Tue Mar 17 11:22:56 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.LoopExplosionPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
-import com.oracle.graal.nodes.*;
-
-public class GraphBuilderConfiguration {
-
-    public static class Plugins {
-        private InvocationPlugins invocationPlugins;
-        private LoadFieldPlugin loadFieldPlugin;
-        private LoadIndexedPlugin loadIndexedPlugin;
-        private ParameterPlugin parameterPlugin;
-        private InlineInvokePlugin inlineInvokePlugin;
-        private GenericInvocationPlugin genericInvocationPlugin;
-        private LoopExplosionPlugin loopExplosionPlugin;
-
-        public Plugins() {
-            invocationPlugins = new InvocationPlugins();
-        }
-
-        public Plugins(InvocationPlugins invocationPlugins) {
-            this.invocationPlugins = invocationPlugins;
-        }
-
-        public InvocationPlugins getInvocationPlugins() {
-            return invocationPlugins;
-        }
-
-        public GenericInvocationPlugin getGenericInvocationPlugin() {
-            return genericInvocationPlugin;
-        }
-
-        public void setGenericInvocationPlugin(GenericInvocationPlugin plugin) {
-            this.genericInvocationPlugin = plugin;
-        }
-
-        public LoadFieldPlugin getLoadFieldPlugin() {
-            return loadFieldPlugin;
-        }
-
-        public void setLoadFieldPlugin(LoadFieldPlugin plugin) {
-            this.loadFieldPlugin = plugin;
-        }
-
-        public LoadIndexedPlugin getLoadIndexedPlugin() {
-            return loadIndexedPlugin;
-        }
-
-        public void setLoadIndexedPlugin(LoadIndexedPlugin plugin) {
-            this.loadIndexedPlugin = plugin;
-        }
-
-        public ParameterPlugin getParameterPlugin() {
-            return parameterPlugin;
-        }
-
-        public void setParameterPlugin(ParameterPlugin plugin) {
-            this.parameterPlugin = plugin;
-        }
-
-        public InlineInvokePlugin getInlineInvokePlugin() {
-            return inlineInvokePlugin;
-        }
-
-        public void setInlineInvokePlugin(InlineInvokePlugin plugin) {
-            this.inlineInvokePlugin = plugin;
-        }
-
-        public LoopExplosionPlugin getLoopExplosionPlugin() {
-            return loopExplosionPlugin;
-        }
-
-        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
-            this.loopExplosionPlugin = plugin;
-        }
-
-        public Plugins updateFrom(Plugins other, boolean includeInvocationPlugins) {
-            if (includeInvocationPlugins) {
-                this.invocationPlugins.updateFrom(other.getInvocationPlugins());
-            }
-            this.parameterPlugin = other.parameterPlugin;
-            this.loadFieldPlugin = other.loadFieldPlugin;
-            this.loadIndexedPlugin = other.loadIndexedPlugin;
-            this.inlineInvokePlugin = other.inlineInvokePlugin;
-            this.loopExplosionPlugin = other.loopExplosionPlugin;
-            this.genericInvocationPlugin = other.genericInvocationPlugin;
-            return this;
-        }
-    }
-
-    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
-
-    private final boolean eagerResolving;
-    private final boolean omitAllExceptionEdges;
-    private final ResolvedJavaType[] skippedExceptionTypes;
-    private final DebugInfoMode debugInfoMode;
-    private final boolean doLivenessAnalysis;
-    private boolean useProfiling;
-    private Plugins plugins = new Plugins();
-
-    public static enum DebugInfoMode {
-        SafePointsOnly,
-        /**
-         * This mode inserts {@link SimpleInfopointNode}s in places where no safepoints would be
-         * inserted: inlining boundaries, and line number switches.
-         * <p>
-         * In this mode the infopoint only have a location (method and bytecode index) and no
-         * values.
-         * <p>
-         * This is useful to have better program counter to bci mapping and has no influence on the
-         * generated code. However it can increase the amount of metadata and does not allow access
-         * to accessing values at runtime.
-         */
-        Simple,
-        /**
-         * In this mode, {@link FullInfopointNode}s are generated in the same locations as in
-         * {@link #Simple} mode but the infopoints have access to the runtime values.
-         * <p>
-         * This is relevant when code is to be generated for native, machine-code level debugging
-         * but can have a limit the amount of optimization applied to the code.
-         */
-        Full,
-    }
-
-    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis) {
-        this.eagerResolving = eagerResolving;
-        this.omitAllExceptionEdges = omitAllExceptionEdges;
-        this.debugInfoMode = debugInfoMode;
-        this.skippedExceptionTypes = skippedExceptionTypes;
-        this.doLivenessAnalysis = doLivenessAnalysis;
-        this.useProfiling = true;
-    }
-
-    public GraphBuilderConfiguration copy() {
-        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis);
-        result.useProfiling = useProfiling;
-        result.copyPluginsFrom(this);
-        return result;
-    }
-
-    public boolean getUseProfiling() {
-        return useProfiling;
-    }
-
-    public void setUseProfiling(boolean b) {
-        this.useProfiling = b;
-    }
-
-    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis);
-    }
-
-    public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
-        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis);
-    }
-
-    public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
-        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis);
-    }
-
-    public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis);
-    }
-
-    public ResolvedJavaType[] getSkippedExceptionTypes() {
-        return skippedExceptionTypes;
-    }
-
-    public boolean eagerResolving() {
-        return eagerResolving;
-    }
-
-    public boolean omitAllExceptionEdges() {
-        return omitAllExceptionEdges;
-    }
-
-    public boolean insertNonSafepointDebugInfo() {
-        return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
-    }
-
-    public boolean insertFullDebugInfo() {
-        return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal();
-    }
-
-    public boolean doLivenessAnalysis() {
-        return doLivenessAnalysis;
-    }
-
-    public static GraphBuilderConfiguration getDefault() {
-        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
-    }
-
-    public static GraphBuilderConfiguration getEagerDefault() {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
-    }
-
-    public static GraphBuilderConfiguration getSnippetDefault() {
-        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
-    }
-
-    public static GraphBuilderConfiguration getFullDebugDefault() {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
-    }
-
-    /**
-     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
-     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
-     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
-     */
-    public boolean unresolvedIsError() {
-        return eagerResolving;
-    }
-
-    public Plugins getPlugins() {
-        return plugins;
-    }
-
-    public void setPlugins(Plugins plugins) {
-        this.plugins = plugins;
-    }
-
-    public GraphBuilderConfiguration copyPluginsFrom(GraphBuilderConfiguration other) {
-        this.plugins.updateFrom(other.plugins, true);
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Tue Mar 17 11:22:56 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +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.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object.
- */
-public interface GraphBuilderContext {
-
-    /**
-     * Information about a snippet or method substitution currently being processed by the graph
-     * builder. When in the scope of a replacement, the graph builder does not check the value kinds
-     * flowing through the JVM state since replacements can employ non-Java kinds to represent
-     * values such as raw machine words and pointers.
-     */
-    public interface Replacement {
-
-        /**
-         * Gets the method being replaced.
-         */
-        ResolvedJavaMethod getOriginalMethod();
-
-        /**
-         * Gets the replacement method.
-         */
-        ResolvedJavaMethod getReplacementMethod();
-
-        /**
-         * Determines if this replacement is being inlined as a compiler intrinsic. A compiler
-         * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler
-         * intrinsic will restart the interpreter at the intrinsified call.
-         */
-        boolean isIntrinsic();
-    }
-
-    <T extends ControlSinkNode> T append(T fixed);
-
-    <T extends ControlSplitNode> T append(T fixed);
-
-    <T extends FixedWithNextNode> T append(T fixed);
-
-    <T extends FloatingNode> T append(T value);
-
-    <T extends ValueNode> T append(T value);
-
-    StampProvider getStampProvider();
-
-    MetaAccessProvider getMetaAccess();
-
-    Assumptions getAssumptions();
-
-    ConstantReflectionProvider getConstantReflection();
-
-    SnippetReflectionProvider getSnippetReflection();
-
-    void push(Kind kind, ValueNode value);
-
-    StructuredGraph getGraph();
-
-    FrameState createStateAfter();
-
-    /**
-     * Gets the parsing context for the method that inlines the method being parsed by this context.
-     */
-    GraphBuilderContext getParent();
-
-    /**
-     * Gets the root method for the graph building process.
-     */
-    ResolvedJavaMethod getRootMethod();
-
-    /**
-     * Gets the method currently being parsed.
-     */
-    ResolvedJavaMethod getMethod();
-
-    /**
-     * Gets the index of the bytecode instruction currently being parsed.
-     */
-    int bci();
-
-    /**
-     * Gets the inline depth of this context. 0 implies this is the context for the
-     * {@linkplain #getRootMethod() root method}.
-     */
-    int getDepth();
-
-    /**
-     * Determines if the current parsing context is a snippet or method substitution.
-     */
-    default boolean parsingReplacement() {
-        return getReplacement() == null;
-    }
-
-    /**
-     * Gets the replacement of the current parsing context or {@code null} if not
-     * {@link #parsingReplacement() parsing a replacement}.
-     */
-    Replacement getReplacement();
-
-    /**
-     * @see GuardingPiNode#nullCheckedValue(ValueNode)
-     */
-    static ValueNode nullCheckedValue(GraphBuilderContext builder, ValueNode value) {
-        ValueNode nonNullValue = GuardingPiNode.nullCheckedValue(value);
-        if (nonNullValue != value) {
-            builder.append((FixedWithNextNode) nonNullValue);
-        }
-        return nonNullValue;
-    }
-
-    boolean eagerResolving();
-
-    BailoutException bailout(String string);
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Mar 17 11:23:06 2015 -0700
@@ -46,14 +46,11 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
 import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
-import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin.InlineInfo;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.LoopExplosionPlugin;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +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 java.lang.reflect.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin.InlineInfo;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Marker interface for graph builder plugins.
- */
-public interface GraphBuilderPlugin {
-
-    public interface LoadFieldPlugin extends GraphBuilderPlugin {
-        @SuppressWarnings("unused")
-        default boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
-            return false;
-        }
-
-        @SuppressWarnings("unused")
-        default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) {
-            return false;
-        }
-
-        default boolean tryConstantFold(GraphBuilderContext b, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant receiver) {
-            JavaConstant result = constantReflection.readConstantFieldValue(field, receiver);
-            if (result != null) {
-                ConstantNode constantNode = b.append(ConstantNode.forConstant(result, metaAccess));
-                b.push(constantNode.getKind().getStackKind(), constantNode);
-                return true;
-            }
-            return false;
-        }
-    }
-
-    public interface LoadIndexedPlugin extends GraphBuilderPlugin {
-        @SuppressWarnings("unused")
-        default boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) {
-            return false;
-        }
-    }
-
-    /**
-     * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined
-     * invocations that result in {@link Invoke} nodes.
-     */
-    public interface InlineInvokePlugin extends GraphBuilderPlugin {
-
-        public static class InlineInfo {
-
-            /**
-             * The method to be inlined.
-             */
-            public final ResolvedJavaMethod methodToInline;
-
-            /**
-             * Specifies if {@link #methodToInline} is to be considered a
-             * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method}
-             * passed to {@link InlineInvokePlugin#getInlineInfo}.
-             */
-            public final boolean isReplacement;
-
-            /**
-             * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so,
-             * any {@link StateSplit} node created in the (recursive) inlining scope will be given a
-             * frame state that restarts the interpreter just before the intrinsified invocation.
-             */
-            public final boolean isIntrinsic;
-
-            public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) {
-                this.methodToInline = methodToInline;
-                this.isIntrinsic = isIntrinsic;
-                this.isReplacement = isReplacement;
-                assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement";
-            }
-        }
-
-        /**
-         * Determines whether a call to a given method is to be inlined.
-         *
-         * @param method the target method of an invoke
-         * @param args the arguments to the invoke
-         * @param returnType the return type derived from {@code method}'s signature
-         */
-        default InlineInfo getInlineInfo(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
-            return null;
-        }
-
-        /**
-         * @param inlinedTargetMethod
-         */
-        default void postInline(ResolvedJavaMethod inlinedTargetMethod) {
-        }
-
-        /**
-         * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined
-         * per {@link #getInlineInfo}.
-         *
-         * @param method the method that was not inlined
-         * @param invoke the invoke node created for the call to {@code method}
-         */
-        default void notifyOfNoninlinedInvoke(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
-        }
-    }
-
-    public interface LoopExplosionPlugin extends GraphBuilderPlugin {
-        boolean shouldExplodeLoops(ResolvedJavaMethod method);
-
-        boolean shouldMergeExplosions(ResolvedJavaMethod method);
-    }
-
-    public interface ParameterPlugin extends GraphBuilderPlugin {
-        FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp);
-    }
-
-    /**
-     * Plugin for handling an invocation based on some property of the method being invoked such as
-     * any annotations it may have.
-     */
-    public interface GenericInvocationPlugin extends GraphBuilderPlugin {
-        /**
-         * Executes this plugin for an invocation of a given method with a given set of arguments.
-         *
-         * @return {@code true} if this plugin handled the invocation, {@code false} if not
-         */
-        boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args);
-    }
-
-    /**
-     * Plugin for handling a specific method invocation.
-     */
-    public interface InvocationPlugin extends GraphBuilderPlugin {
-        /**
-         * @see #execute
-         */
-        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
-            throw invalidHandler(b, targetMethod);
-        }
-
-        /**
-         * @see #execute
-         */
-        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
-            throw invalidHandler(b, targetMethod, arg);
-        }
-
-        /**
-         * @see #execute
-         */
-        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) {
-            throw invalidHandler(b, targetMethod, arg1, arg2);
-        }
-
-        /**
-         * @see #execute
-         */
-        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-            throw invalidHandler(b, targetMethod, arg1, arg2, arg3);
-        }
-
-        /**
-         * @see #execute
-         */
-        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
-            throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4);
-        }
-
-        /**
-         * @see #execute
-         */
-        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
-            throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5);
-        }
-
-        default ResolvedJavaMethod getSubstitute() {
-            return null;
-        }
-
-        boolean ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING = false;
-
-        /**
-         * Executes a given plugin against a set of invocation arguments by dispatching to the
-         * {@code apply(...)} method that matches the number of arguments.
-         *
-         * @param targetMethod the method for which plugin is being applied
-         * @return {@code true} if the plugin handled the invocation of {@code targetMethod}
-         *         {@code false} if the graph builder should process the invoke further (e.g., by
-         *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
-         *         invocation must not modify the graph being constructed.
-         */
-        static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) {
-            if (ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING) {
-                ResolvedJavaMethod subst = plugin.getSubstitute();
-                if (subst != null) {
-                    return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, true, false), args);
-                }
-            }
-            if (args.length == 0) {
-                return plugin.apply(b, targetMethod);
-            } else if (args.length == 1) {
-                return plugin.apply(b, targetMethod, args[0]);
-            } else if (args.length == 2) {
-                return plugin.apply(b, targetMethod, args[0], args[1]);
-            } else if (args.length == 3) {
-                return plugin.apply(b, targetMethod, args[0], args[1], args[2]);
-            } else if (args.length == 4) {
-                return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]);
-            } else if (args.length == 5) {
-                return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]);
-            } else {
-                throw plugin.invalidHandler(b, targetMethod, args);
-            }
-        }
-
-        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) {
-            return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
-        }
-
-        default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
-            Class<?> c = getClass();
-            for (Method m : c.getDeclaredMethods()) {
-                if (m.getName().equals("apply")) {
-                    return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
-                }
-            }
-            throw new GraalInternalError("could not find method named \"apply\" in " + c.getName());
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Tue Mar 17 11:23:06 2015 -0700
@@ -31,10 +31,10 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Tue Mar 17 11:22:56 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +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 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.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.nodes.*;
-
-/**
- * Manages a set of {@link InvocationPlugin}s.
- */
-public class InvocationPlugins {
-    /**
-     * Utility for {@linkplain InvocationPlugins#register(ResolvedJavaMethod, InvocationPlugin)
-     * registration} of invocation 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 InvocationPlugins plugins;
-        private final MetaAccessProvider metaAccess;
-        private final Class<?> declaringClass;
-
-        /**
-         * Creates an object for registering {@link InvocationPlugin}s 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(InvocationPlugins 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) {
-            plugins.register(arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg), 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) {
-            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2), 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) {
-            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3), plugin);
-        }
-
-        /**
-         * Registers a plugin for a method with 4 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4), plugin);
-        }
-
-        /**
-         * Registers a plugin for a method with 5 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register5(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, Class<?> arg5, InvocationPlugin plugin) {
-            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4, arg5) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4, arg5),
-                            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);
-            }
-        }
-    }
-
-    private final Map<ResolvedJavaMethod, InvocationPlugin> plugins = new HashMap<>();
-
-    /**
-     * The invocation plugins deferred to if a plugin is not found in this object.
-     */
-    private InvocationPlugins defaults;
-
-    /**
-     * 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 Checker.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) {
-        InvocationPlugin res = plugins.get(method);
-        if (res == null && defaults != null) {
-            return defaults.lookupInvocation(method);
-        }
-        return res;
-    }
-
-    /**
-     * Sets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} if a
-     * plugin is not found in this object.
-     */
-    public InvocationPlugins setDefaults(InvocationPlugins defaults) {
-        InvocationPlugins old = this.defaults;
-        this.defaults = defaults;
-        return old;
-    }
-
-    /**
-     * Adds all the plugins from {@code other} to this object.
-     */
-    public void updateFrom(InvocationPlugins other) {
-        this.plugins.putAll(other.plugins);
-        if (other.defaults != null) {
-            updateFrom(other.defaults);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", ")) + " / defaults: " + this.defaults;
-    }
-
-    private static class Checker {
-        private static final int MAX_ARITY = 5;
-        /**
-         * The set of all {@link InvocationPlugin#apply} method signatures.
-         */
-        static final Class<?>[][] SIGS;
-        static {
-            ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
-            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
-                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
-                    Class<?>[] sig = method.getParameterTypes();
-                    assert sig[0] == GraphBuilderContext.class;
-                    assert sig[1] == ResolvedJavaMethod.class;
-                    assert Arrays.asList(Arrays.copyOfRange(sig, 2, sig.length)).stream().allMatch(c -> c == ValueNode.class);
-                    while (sigs.size() < sig.length - 1) {
-                        sigs.add(null);
-                    }
-                    sigs.set(sig.length - 2, sig);
-                }
-            }
-            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
-                            ValueNode.class.getSimpleName());
-            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
-        }
-
-        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)"));
-            for (Method m : plugin.getClass().getDeclaredMethods()) {
-                if (m.getName().equals("apply")) {
-                    Class<?>[] parameterTypes = m.getParameterTypes();
-                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
-                        return true;
-                    }
-                }
-            }
-            throw new AssertionError(format("graph builder plugin for %s not found", method.format("%H.%n(%p)")));
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Tue Mar 17 11:23:06 2015 -0700
@@ -41,7 +41,8 @@
      * Performs control flow optimizations on the given LIR graph.
      */
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
         LIR lir = lirGenRes.getLIR();
         new Optimizer<B>(lir).deleteEmptyBlocks(codeEmittingOrder);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Tue Mar 17 11:23:06 2015 -0700
@@ -51,7 +51,8 @@
 public final class EdgeMoveOptimizer extends PostAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
         LIR ir = lirGenRes.getLIR();
         Optimizer optimizer = new Optimizer(ir);
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Tue Mar 17 11:23:06 2015 -0700
@@ -34,7 +34,8 @@
 public final class NullCheckOptimizer extends PostAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
         LIR ir = lirGenRes.getLIR();
         List<? extends AbstractBlockBase<?>> blocks = ir.codeEmittingOrder();
         NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Mar 17 11:23:06 2015 -0700
@@ -44,7 +44,8 @@
 public final class RedundantMoveElimination extends PostAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
         Optimization redundantMoveElimination = new Optimization();
         redundantMoveElimination.doOptimize(lirGenRes.getLIR(), lirGenRes.getFrameMap());
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/BenchmarkCounterFactory.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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.lir.gen;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.*;
+
+public interface BenchmarkCounterFactory {
+    LIRInstruction createBenchmarkCounter(String name, String group, Value increment);
+
+    LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments);
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Mar 17 11:23:06 2015 -0700
@@ -391,4 +391,12 @@
     public void emitBlackhole(Value operand) {
         append(new StandardOp.BlackholeOp(operand));
     }
+
+    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
+        throw GraalInternalError.unimplemented();
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Mar 17 11:23:06 2015 -0700
@@ -30,7 +30,7 @@
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.lir.*;
 
-public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
+public interface LIRGeneratorTool extends ArithmeticLIRGenerator, BenchmarkCounterFactory {
 
     public interface SpillMoveFactory {
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhaseSuite.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhaseSuite.java	Tue Mar 17 11:23:06 2015 -0700
@@ -28,7 +28,7 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.gen.*;
 
-public abstract class LIRPhaseSuite<C> extends LIRPhase<C> {
+public class LIRPhaseSuite<C> extends LIRPhase<C> {
     private final List<LIRPhase<C>> phases;
 
     public LIRPhaseSuite() {
@@ -75,4 +75,9 @@
         }
     }
 
+    public LIRPhaseSuite<C> copy() {
+        LIRPhaseSuite<C> suite = new LIRPhaseSuite<>();
+        suite.phases.addAll(phases);
+        return suite;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRSuites.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRSuites.java	Tue Mar 17 11:23:06 2015 -0700
@@ -41,6 +41,10 @@
         this.postAllocStage = postAllocStage;
     }
 
+    public LIRSuites(LIRSuites other) {
+        this(other.getPreAllocationOptimizationStage().copy(), other.getAllocationStage().copy(), other.getPostAllocationOptimizationStage().copy());
+    }
+
     /**
      * {@link PreAllocationOptimizationPhase}s are executed between {@link LIR} generation and
      * register allocation.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationPhase.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationPhase.java	Tue Mar 17 11:23:06 2015 -0700
@@ -31,14 +31,20 @@
 public abstract class PostAllocationOptimizationPhase extends LIRPhase<PostAllocationOptimizationPhase.PostAllocationOptimizationContext> {
 
     public static final class PostAllocationOptimizationContext {
+        private final BenchmarkCounterFactory counterFactory;
+
+        public PostAllocationOptimizationContext(BenchmarkCounterFactory counterFactory) {
+            this.counterFactory = counterFactory;
+        }
     }
 
     @Override
     protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
                     PostAllocationOptimizationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.counterFactory);
     }
 
-    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
+    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory);
 
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationStage.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationStage.java	Tue Mar 17 11:23:06 2015 -0700
@@ -25,7 +25,8 @@
 import static com.oracle.graal.lir.phases.LIRPhase.Options.*;
 
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.*;
+import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import com.oracle.graal.lir.profiling.*;
 import com.oracle.graal.options.*;
 
 public class PostAllocationOptimizationStage extends LIRPhaseSuite<PostAllocationOptimizationContext> {
@@ -39,6 +40,8 @@
         public static final NestedBooleanOptionValue LIROptRedundantMoveElimination = new NestedBooleanOptionValue(LIROptimization, true);
         @Option(help = "", type = OptionType.Debug)
         public static final NestedBooleanOptionValue LIROptNullCheckOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptMoveProfiling = new OptionValue<>(false);
         // @formatter:on
     }
 
@@ -55,5 +58,8 @@
         if (Options.LIROptNullCheckOptimizer.getValue()) {
             appendPhase(new NullCheckOptimizer());
         }
+        if (Options.LIROptMoveProfiling.getValue()) {
+            appendPhase(new MoveProfiling());
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,148 @@
+/*
+ * 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.lir.profiling;
+
+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.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
+
+public class MoveProfiling extends PostAllocationOptimizationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
+        new Analyzer(lirGenRes.getLIR(), counterFactory).run();
+    }
+
+    private static enum MoveType {
+        REG2REG("Reg", "Reg"),
+        STACK2REG("Reg", "Stack"),
+        CONST2REG("Reg", "Const"),
+        REG2STACK("Stack", "Reg"),
+        CONST2STACK("Stack", "Const");
+
+        private final String name;
+
+        MoveType(String dst, String src) {
+            this.name = String.format("%5s <- %s", dst, src);
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        public static MoveType get(MoveOp move) {
+            AllocatableValue dst = move.getResult();
+            Value src = move.getInput();
+            if (isRegister(dst)) {
+                if (isRegister(src)) {
+                    return REG2REG;
+                }
+                if (isStackSlot(src)) {
+                    return STACK2REG;
+                }
+                if (isConstant(src)) {
+                    return CONST2REG;
+                }
+            } else if (isStackSlot(dst)) {
+                if (isRegister(src)) {
+                    return REG2STACK;
+                }
+                if (isConstant(src)) {
+                    return CONST2STACK;
+                }
+            }
+            throw GraalInternalError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", move, dst, src));
+        }
+    }
+
+    private static class Analyzer {
+        private final LIR lir;
+        private final BenchmarkCounterFactory counterFactory;
+        private final LIRInsertionBuffer buffer;
+        private final int[] cnt;
+
+        public Analyzer(LIR lir, BenchmarkCounterFactory counterFactory) {
+            this.lir = lir;
+            this.counterFactory = counterFactory;
+            this.buffer = new LIRInsertionBuffer();
+            cnt = new int[MoveType.values().length];
+        }
+
+        public void run() {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        }
+
+        public void doBlock(AbstractBlockBase<?> block) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
+            assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
+            assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
+            assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
+            assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
+
+            // reset counters
+            Arrays.fill(cnt, 0);
+            // analysis phase
+            for (LIRInstruction inst : instructions) {
+                if (inst instanceof MoveOp) {
+                    cnt[MoveType.get((MoveOp) inst).ordinal()]++;
+                }
+            }
+
+            // counter insertion phase
+            List<String> names = new ArrayList<>();
+            List<Value> increments = new ArrayList<>();
+            for (MoveType type : MoveType.values()) {
+                int i = cnt[type.ordinal()];
+                if (i > 0) {
+                    names.add(type.toString());
+                    increments.add(JavaConstant.forInt(i));
+                }
+            }
+            String[] groups = new String[names.size()];
+            Arrays.fill(groups, "Move Operations");
+
+            LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
+            assert inst != null;
+            buffer.init(instructions);
+            buffer.append(1, inst);
+            buffer.finish();
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Mar 17 11:23:06 2015 -0700
@@ -237,15 +237,21 @@
         if (this.killLocationsBetweenThisAndDominator == null) {
             LocationSet dominatorResult = new LocationSet();
             Block stopBlock = getDominator();
-            for (Block b : this.getPredecessors()) {
-                if (b != stopBlock && (!this.isLoopHeader() || b.getLoopDepth() < this.getLoopDepth())) {
-                    dominatorResult.addAll(b.getKillLocations());
-                    if (dominatorResult.isAny()) {
-                        break;
-                    }
-                    b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
-                    if (dominatorResult.isAny()) {
-                        break;
+            if (this.isLoopHeader()) {
+                assert stopBlock.getLoopDepth() < this.getLoopDepth();
+                dominatorResult.addAll(((HIRLoop) this.getLoop()).getKillLocations());
+            } else {
+                for (Block b : this.getPredecessors()) {
+                    assert !this.isLoopHeader();
+                    if (b != stopBlock) {
+                        dominatorResult.addAll(b.getKillLocations());
+                        if (dominatorResult.isAny()) {
+                            break;
+                        }
+                        b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
+                        if (dominatorResult.isAny()) {
+                            break;
+                        }
                     }
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Tue Mar 17 11:23:06 2015 -0700
@@ -39,7 +39,7 @@
         return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count();
     }
 
-    private LocationSet getKillLocations() {
+    public LocationSet getKillLocations() {
         if (killLocations == null) {
             killLocations = new LocationSet();
             for (Block b : this.getBlocks()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -22,8 +22,11 @@
  */
 package com.oracle.graal.nodes.debug;
 
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,7 +40,7 @@
  * value of withContext, the name of the root method is added to the counter's name.
  */
 @NodeInfo
-public class DynamicCounterNode extends FixedWithNextNode implements Lowerable {
+public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<DynamicCounterNode> TYPE = NodeClass.create(DynamicCounterNode.class);
     @Input ValueNode increment;
@@ -74,11 +77,6 @@
         return withContext;
     }
 
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-
     public static void addCounterBefore(String group, String name, long increment, boolean withContext, FixedNode position) {
         StructuredGraph graph = position.graph();
         graph.addBeforeFixed(position, position.graph().add(new DynamicCounterNode(name, group, ConstantNode.forLong(increment, position.graph()), withContext)));
@@ -87,4 +85,32 @@
     @NodeIntrinsic
     public static native void counter(@ConstantNodeParameter String name, @ConstantNodeParameter String group, long increment, @ConstantNodeParameter boolean addContext);
 
+    public void generate(NodeLIRBuilderTool generator) {
+        LIRGeneratorTool lirGen = generator.getLIRGeneratorTool();
+        String nameWithContext;
+        if (isWithContext()) {
+            nameWithContext = getName() + " @ ";
+            if (graph().method() != null) {
+                StackTraceElement stackTraceElement = graph().method().asStackTraceElement(0);
+                if (stackTraceElement != null) {
+                    nameWithContext += " " + stackTraceElement.toString();
+                } else {
+                    nameWithContext += graph().method().format("%h.%n");
+                }
+            }
+            if (graph().name != null) {
+                nameWithContext += " (" + graph().name + ")";
+            }
+
+        } else {
+            nameWithContext = getName();
+        }
+        LIRInstruction counterOp = lirGen.createBenchmarkCounter(nameWithContext, getGroup(), generator.operand(increment));
+        if (counterOp != null) {
+            lirGen.append(counterOp);
+        } else {
+            throw GraalInternalError.unimplemented("Benchmark counters not enabled or not implemented by the back end.");
+        }
+    }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -79,7 +79,6 @@
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
         // the monitor exit for a synchronized method should never be virtualized
-        assert stateAfter().bci != BytecodeFrame.AFTER_BCI || state == null;
         if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
             MonitorIdNode removedLock = state.removeLock();
             assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,147 @@
+/*
+ * 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.phases.schedule;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+
+public final class MemoryScheduleVerification extends BlockIteratorClosure<Set<FloatingReadNode>> {
+
+    private final BlockMap<List<Node>> blockToNodesMap;
+
+    public static boolean check(Block startBlock, BlockMap<List<Node>> blockToNodesMap) {
+        ReentrantBlockIterator.apply(new MemoryScheduleVerification(blockToNodesMap), startBlock);
+        return true;
+    }
+
+    private MemoryScheduleVerification(BlockMap<List<Node>> blockToNodesMap) {
+        this.blockToNodesMap = blockToNodesMap;
+    }
+
+    @Override
+    protected Set<FloatingReadNode> getInitialState() {
+        return CollectionsFactory.newSet();
+    }
+
+    @Override
+    protected Set<FloatingReadNode> processBlock(Block block, Set<FloatingReadNode> currentState) {
+        for (Node n : blockToNodesMap.get(block)) {
+            if (n instanceof AbstractMergeNode) {
+                AbstractMergeNode abstractMergeNode = (AbstractMergeNode) n;
+                for (PhiNode phi : abstractMergeNode.phis()) {
+                    if (phi instanceof MemoryPhiNode) {
+                        MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
+                        addFloatingReadUsages(currentState, memoryPhiNode);
+                    }
+                }
+
+            }
+
+            if (n instanceof MemoryCheckpoint) {
+                if (n instanceof MemoryCheckpoint.Single) {
+                    MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
+                    processLocation(n, single.getLocationIdentity(), currentState);
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
+                    for (LocationIdentity location : multi.getLocationIdentities()) {
+                        processLocation(n, location, currentState);
+                    }
+                }
+
+                addFloatingReadUsages(currentState, n);
+            } else if (n instanceof FloatingReadNode) {
+                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                if (floatingReadNode.getLastLocationAccess() != null && floatingReadNode.getLocationIdentity().isMutable()) {
+                    if (currentState.contains(floatingReadNode)) {
+                        // Floating read was found in the state.
+                        currentState.remove(floatingReadNode);
+                    } else {
+                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule");
+                    }
+                }
+
+            }
+        }
+        return currentState;
+    }
+
+    private static void addFloatingReadUsages(Set<FloatingReadNode> currentState, Node n) {
+        for (FloatingReadNode read : n.usages().filter(FloatingReadNode.class)) {
+            if (read.getLastLocationAccess() == n && read.getLocationIdentity().isMutable()) {
+                currentState.add(read);
+            }
+        }
+    }
+
+    private void processLocation(Node n, LocationIdentity location, Set<FloatingReadNode> currentState) {
+        assert n != null;
+        if (location.isImmutable()) {
+            return;
+        }
+
+        for (FloatingReadNode r : cloneState(currentState)) {
+            if (r.getLocationIdentity().overlaps(location)) {
+                // This read is killed by this location.
+                currentState.remove(r);
+            }
+        }
+    }
+
+    @Override
+    protected Set<FloatingReadNode> merge(Block merge, List<Set<FloatingReadNode>> states) {
+        Set<FloatingReadNode> result = states.get(0);
+        for (int i = 1; i < states.size(); ++i) {
+            result.retainAll(states.get(i));
+        }
+        return result;
+    }
+
+    @Override
+    protected Set<FloatingReadNode> cloneState(Set<FloatingReadNode> oldState) {
+        Set<FloatingReadNode> result = CollectionsFactory.newSet();
+        result.addAll(oldState);
+        return result;
+    }
+
+    @Override
+    protected List<Set<FloatingReadNode>> processLoop(Loop<Block> loop, Set<FloatingReadNode> initialState) {
+        HIRLoop l = (HIRLoop) loop;
+        for (MemoryPhiNode memoryPhi : ((LoopBeginNode) l.getHeader().getBeginNode()).phis().filter(MemoryPhiNode.class)) {
+            for (FloatingReadNode r : cloneState(initialState)) {
+                if (r.getLocationIdentity().overlaps(memoryPhi.getLocationIdentity())) {
+                    initialState.remove(r);
+                }
+            }
+        }
+        return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Mar 17 11:23:06 2015 -0700
@@ -94,6 +94,7 @@
         cfg = ControlFlowGraph.compute(graph, true, true, true, false);
 
         if (selectedStrategy == SchedulingStrategy.EARLIEST) {
+            // Assign early so we are getting a context in case of an exception.
             this.nodeToBlockMap = graph.createNodeMap();
             this.blockToNodesMap = new BlockMap<>(cfg);
             NodeBitMap visited = graph.createNodeBitMap();
@@ -105,6 +106,11 @@
                 NodeMap<Block> currentNodeMap = graph.createNodeMap();
                 BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
                 NodeBitMap visited = graph.createNodeBitMap();
+
+                // Assign early so we are getting a context in case of an exception.
+                this.blockToNodesMap = earliestBlockToNodesMap;
+                this.nodeToBlockMap = currentNodeMap;
+
                 scheduleEarliestIterative(cfg, earliestBlockToNodesMap, currentNodeMap, visited, graph);
                 BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
 
@@ -115,10 +121,12 @@
                 BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(isOutOfLoops, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap);
                 sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
 
+                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
+                assert MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
+
                 this.blockToNodesMap = latestBlockToNodesMap;
                 this.nodeToBlockMap = currentNodeMap;
 
-                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
                 cfg.setNodeToBlock(currentNodeMap);
             }
         }
@@ -165,7 +173,7 @@
                                     // We are not constraint within currentBlock. Check if
                                     // we are contraint while walking down the dominator
                                     // line.
-                                    Block newLatestBlock = adjustLatestForRead(currentBlock, latestBlock, location);
+                                    Block newLatestBlock = adjustLatestForRead(floatingReadNode, currentBlock, latestBlock, location);
                                     assert dominates(newLatestBlock, latestBlock);
                                     assert dominates(currentBlock, newLatestBlock);
                                     latestBlock = newLatestBlock;
@@ -203,7 +211,7 @@
         return true;
     }
 
-    private static Block adjustLatestForRead(Block earliestBlock, Block latestBlock, LocationIdentity location) {
+    private static Block adjustLatestForRead(FloatingReadNode floatingReadNode, Block earliestBlock, Block latestBlock, LocationIdentity location) {
         assert strictlyDominates(earliestBlock, latestBlock);
         Block current = latestBlock.getDominator();
 
@@ -218,6 +226,7 @@
             }
             dominatorChain.add(current);
             current = current.getDominator();
+            assert current != null : floatingReadNode;
         }
 
         // The first element of dominatorChain now contains the latest possible block.
@@ -291,7 +300,7 @@
             for (ProxyNode proxy : loopExitNode.proxies()) {
                 unprocessed.clear(proxy);
                 ValueNode value = proxy.value();
-                if (nodeMap.get(value) == b) {
+                if (value != null && nodeMap.get(value) == b) {
                     sortIntoList(value, b, result, nodeMap, unprocessed, null);
                 }
             }
@@ -537,6 +546,8 @@
                 }
             }
         }
+
+        assert MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
     }
 
     private static void resortEarliestWithinBlock(Block b, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap unprocessed) {
@@ -550,7 +561,7 @@
                 MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess();
                 if (locationIdentity.isMutable() && lastLocationAccess != null) {
                     ValueNode lastAccessLocation = lastLocationAccess.asNode();
-                    if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode) {
+                    if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode && !(lastAccessLocation instanceof MemoryPhiNode)) {
                         // This node's last access location is within this block. Add to watch list
                         // when processing the last access location.
                     } else {
@@ -650,16 +661,22 @@
                         assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg.";
                         Block earliest = startBlock;
                         for (Node input : current.inputs()) {
-                            Block inputEarliest;
-                            if (input instanceof ControlSplitNode) {
-                                inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
-                            } else {
-                                inputEarliest = nodeToBlock.get(input);
-                            }
+                            Block inputEarliest = nodeToBlock.get(input);
                             if (inputEarliest == null) {
                                 assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current;
                             } else {
                                 assert inputEarliest != null;
+                                if (inputEarliest.getEndNode() == input) {
+                                    // This is the last node of the block.
+                                    if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                                        // Keep regular inputEarliest.
+                                    } else if (input instanceof ControlSplitNode) {
+                                        inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
+                                    } else {
+                                        assert inputEarliest.getSuccessorCount() == 1;
+                                        inputEarliest = inputEarliest.getSuccessors().get(0);
+                                    }
+                                }
                                 if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
                                     earliest = inputEarliest;
                                 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ConstantBindingParameterPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ConstantBindingParameterPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -25,8 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -31,8 +31,7 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.word.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Mar 17 11:23:06 2015 -0700
@@ -45,7 +45,6 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.util.*;
 
 /**
  * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with
@@ -53,12 +52,19 @@
  */
 public class NodeIntrinsificationPhase extends Phase {
 
-    private final Providers providers;
+    private final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
     private final SnippetReflectionProvider snippetReflection;
+    private final ForeignCallsProvider foreignCalls;
+    private final StampProvider stampProvider;
 
-    public NodeIntrinsificationPhase(Providers providers, SnippetReflectionProvider snippetReflection) {
-        this.providers = providers;
+    public NodeIntrinsificationPhase(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls,
+                    StampProvider stampProvider) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
         this.snippetReflection = snippetReflection;
+        this.foreignCalls = foreignCalls;
+        this.stampProvider = stampProvider;
     }
 
     @Override
@@ -101,7 +107,7 @@
 
             if (constant != null) {
                 // Replace the invoke with the result of the call
-                ConstantNode node = ConstantNode.forConstant(constant, providers.getMetaAccess(), methodCallTargetNode.graph());
+                ConstantNode node = ConstantNode.forConstant(constant, metaAccess, methodCallTargetNode.graph());
                 methodCallTargetNode.invoke().intrinsify(node);
 
                 // Clean up checkcast instructions inserted by javac if the return type is generic.
@@ -165,7 +171,7 @@
         if (intrinsic.foldable() && areAllConstant(arguments)) {
             JavaConstant res = tryFold(arguments, parameterTypes, method);
             if (!res.equals(COULD_NOT_FOLD)) {
-                return ConstantNode.forConstant(res, providers.getMetaAccess());
+                return ConstantNode.forConstant(res, metaAccess);
             }
         }
 
@@ -220,12 +226,12 @@
                  * For intrinsification (but not for folding) if we have a Class<?> object we want
                  * the corresponding ResolvedJavaType.
                  */
-                ResolvedJavaType type = folding ? null : providers.getConstantReflection().asJavaType(constant);
+                ResolvedJavaType type = folding ? null : constantReflection.asJavaType(constant);
                 Object arg;
                 if (type != null) {
                     /* If we found such a type then it's our arg */
                     arg = type;
-                    parameterTypes[i] = providers.getMetaAccess().lookupJavaType(ResolvedJavaType.class);
+                    parameterTypes[i] = metaAccess.lookupJavaType(ResolvedJavaType.class);
                 } else {
                     JavaConstant javaConstant = (JavaConstant) constant;
                     if (folding) {
@@ -253,7 +259,7 @@
                 reflectionCallArguments[i] = arg;
             } else {
                 reflectionCallArguments[i] = argument;
-                parameterTypes[i] = providers.getMetaAccess().lookupJavaType(ValueNode.class);
+                parameterTypes[i] = metaAccess.lookupJavaType(ValueNode.class);
             }
         }
         return reflectionCallArguments;
@@ -264,10 +270,10 @@
         if (intrinsic.value() == NodeIntrinsic.class) {
             result = target.getDeclaringClass();
         } else {
-            result = providers.getMetaAccess().lookupJavaType(intrinsic.value());
+            result = metaAccess.lookupJavaType(intrinsic.value());
         }
-        assert providers.getMetaAccess().lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + result.toJavaName(false) + " derived from @" +
-                        NodeIntrinsic.class.getSimpleName() + " annotation on " + target.format("%H.%n(%p)") + " is not a subclass of " + ValueNode.class;
+        assert metaAccess.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + result.toJavaName(false) + " derived from @" + NodeIntrinsic.class.getSimpleName() +
+                        " annotation on " + target.format("%H.%n(%p)") + " is not a subclass of " + ValueNode.class;
         return result;
     }
 
@@ -339,7 +345,6 @@
         Object[] injected = null;
 
         ResolvedJavaType[] signature = resolveJavaTypes(c.getSignature().toParameterTypes(null), c.getDeclaringClass());
-        MetaAccessProvider metaAccess = providers.getMetaAccess();
         for (int i = 0; i < signature.length; i++) {
             if (c.getParameterAnnotation(InjectedNodeParameter.class, i) != null) {
                 injected = injected == null ? new Object[1] : Arrays.copyOf(injected, injected.length + 1);
@@ -351,13 +356,13 @@
                 } else if (signature[i].equals(metaAccess.lookupJavaType(StructuredGraph.class))) {
                     injected[injected.length - 1] = graph;
                 } else if (signature[i].equals(metaAccess.lookupJavaType(ForeignCallsProvider.class))) {
-                    injected[injected.length - 1] = providers.getForeignCalls();
+                    injected[injected.length - 1] = foreignCalls;
                 } else if (signature[i].equals(metaAccess.lookupJavaType(SnippetReflectionProvider.class))) {
                     injected[injected.length - 1] = snippetReflection;
                 } else if (signature[i].isAssignableFrom(metaAccess.lookupJavaType(Stamp.class))) {
                     injected[injected.length - 1] = invokeStamp;
                 } else if (signature[i].isAssignableFrom(metaAccess.lookupJavaType(StampProvider.class))) {
-                    injected[injected.length - 1] = providers.getStampProvider();
+                    injected[injected.length - 1] = stampProvider;
                 } else {
                     throw new GraalInternalError("Cannot handle injected argument of type %s in %s", signature[i].toJavaName(), c.format("%H.%n(%p)"));
                 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Mar 17 11:23:06 2015 -0700
@@ -42,9 +42,10 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
@@ -71,7 +72,8 @@
      */
     protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
 
-    public void completeInitialization(GraphBuilderConfiguration.Plugins plugins) {
+    public void setGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
+        assert this.graphBuilderPlugins == null;
         this.graphBuilderPlugins = plugins;
     }
 
@@ -299,7 +301,7 @@
     }
 
     protected NodeIntrinsificationPhase createNodeIntrinsificationPhase() {
-        return new NodeIntrinsificationPhase(providers, snippetReflection);
+        return new NodeIntrinsificationPhase(providers.getMetaAccess(), providers.getConstantReflection(), snippetReflection, providers.getForeignCalls(), providers.getStampProvider());
     }
 
     @Override
@@ -640,9 +642,8 @@
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
-                    Plugins plugins = config.getPlugins().updateFrom(replacements.graphBuilderPlugins, false);
-                    plugins.getInvocationPlugins().setDefaults(replacements.graphBuilderPlugins.getInvocationPlugins());
+                    Plugins plugins = new Plugins(replacements.graphBuilderPlugins);
+                    GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
                     if (args != null) {
                         plugins.setParameterPlugin(new ConstantBindingParameterPlugin(args, plugins.getParameterPlugin(), metaAccess, replacements.snippetReflection));
                     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Mar 17 11:23:06 2015 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.java.GraphBuilderContext.*;
+import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
 import static com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation.*;
 import sun.misc.*;
 
@@ -32,10 +32,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.java.InvocationPlugins.Registration;
-import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
@@ -57,29 +55,29 @@
     // @formatter:on
 
     public static void registerInvocationPlugins(MetaAccessProvider metaAccess, Architecture arch, InvocationPlugins plugins, boolean useBoxingPlugins) {
-        registerObjectPlugins(metaAccess, plugins);
-        registerClassPlugins(metaAccess, plugins);
-        registerMathPlugins(metaAccess, arch, plugins);
-        registerUnsignedMathPlugins(metaAccess, plugins);
-        registerCharacterPlugins(metaAccess, plugins);
-        registerShortPlugins(metaAccess, plugins);
-        registerIntegerLongPlugins(metaAccess, plugins, Kind.Int);
-        registerIntegerLongPlugins(metaAccess, plugins, Kind.Long);
-        registerFloatPlugins(metaAccess, plugins);
-        registerDoublePlugins(metaAccess, plugins);
-        registerUnsafePlugins(metaAccess, arch, plugins);
+        registerObjectPlugins(plugins);
+        registerClassPlugins(plugins);
+        registerMathPlugins(arch, plugins);
+        registerUnsignedMathPlugins(plugins);
+        registerCharacterPlugins(plugins);
+        registerShortPlugins(plugins);
+        registerIntegerLongPlugins(plugins, Kind.Int);
+        registerIntegerLongPlugins(plugins, Kind.Long);
+        registerFloatPlugins(plugins);
+        registerDoublePlugins(plugins);
+        registerUnsafePlugins(arch, plugins);
         registerEdgesPlugins(metaAccess, plugins);
-        registerGraalDirectivesPlugins(metaAccess, plugins);
+        registerGraalDirectivesPlugins(plugins);
         if (useBoxingPlugins) {
-            registerBoxingPlugins(metaAccess, plugins);
+            registerBoxingPlugins(plugins);
         }
         if (Options.UseBlackholeSubstitution.getValue()) {
-            registerJMHBlackholePlugins(metaAccess, plugins);
+            registerJMHBlackholePlugins(plugins);
         }
     }
 
-    private static void registerUnsafePlugins(MetaAccessProvider metaAccess, Architecture arch, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Unsafe.class);
+    private static void registerUnsafePlugins(Architecture arch, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Unsafe.class);
         for (Kind kind : Kind.values()) {
             if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) {
                 Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
@@ -147,10 +145,10 @@
         return arch.getName().equals("AMD64");
     }
 
-    private static void registerIntegerLongPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins, Kind kind) {
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Kind kind) {
         Class<?> declaringClass = kind.toBoxedJavaClass();
         Class<?> type = kind.toJavaClass();
-        Registration r = new Registration(plugins, metaAccess, declaringClass);
+        Registration r = new Registration(plugins, declaringClass);
         r.register1("reverseBytes", type, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 b.push(kind, b.append(new ReverseBytesNode(value).canonical(null, value)));
@@ -177,8 +175,8 @@
         });
     }
 
-    private static void registerCharacterPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Character.class);
+    private static void registerCharacterPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Character.class);
         r.register1("reverseBytes", char.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 // return (char) (Integer.reverse(i) >> 16);
@@ -191,8 +189,8 @@
         });
     }
 
-    private static void registerShortPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Short.class);
+    private static void registerShortPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Short.class);
         r.register1("reverseBytes", short.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 // return (short) (Integer.reverse(i) >> 16);
@@ -205,8 +203,8 @@
         });
     }
 
-    private static void registerFloatPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Float.class);
+    private static void registerFloatPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Float.class);
         r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 b.push(Kind.Int, b.append(new ReinterpretNode(Kind.Int, value).canonical(null, value)));
@@ -221,8 +219,8 @@
         });
     }
 
-    private static void registerDoublePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Double.class);
+    private static void registerDoublePlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Double.class);
         r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 b.push(Kind.Long, b.append(new ReinterpretNode(Kind.Long, value).canonical(null, value)));
@@ -237,8 +235,8 @@
         });
     }
 
-    private static void registerMathPlugins(MetaAccessProvider metaAccess, Architecture arch, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Math.class);
+    private static void registerMathPlugins(Architecture arch, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Math.class);
         r.register1("abs", Float.TYPE, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 b.push(Kind.Float, b.append(new AbsNode(value).canonical(null, value)));
@@ -303,8 +301,8 @@
         }
     }
 
-    private static void registerUnsignedMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, UnsignedMath.class);
+    private static void registerUnsignedMathPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, UnsignedMath.class);
         r.register2("aboveThan", int.class, int.class, new UnsignedMathPlugin(Condition.AT));
         r.register2("aboveThan", long.class, long.class, new UnsignedMathPlugin(Condition.AT));
         r.register2("belowThan", int.class, int.class, new UnsignedMathPlugin(Condition.BT));
@@ -339,17 +337,17 @@
         });
     }
 
-    protected static void registerBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    protected static void registerBoxingPlugins(InvocationPlugins plugins) {
         for (Kind kind : Kind.values()) {
             if (kind.isPrimitive() && kind != Kind.Void) {
-                new BoxPlugin(kind).register(metaAccess, plugins);
-                new UnboxPlugin(kind).register(metaAccess, plugins);
+                new BoxPlugin(kind).register(plugins);
+                new UnboxPlugin(kind).register(plugins);
             }
         }
     }
 
-    private static void registerObjectPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Object.class);
+    private static void registerObjectPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Object.class);
         r.register1("<init>", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) {
                 if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
@@ -362,8 +360,8 @@
         });
     }
 
-    private static void registerClassPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Class.class);
+    private static void registerClassPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Class.class);
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) {
                 ValueNode nullCheckedType = nullCheckedValue(b, type);
@@ -401,7 +399,7 @@
      * project containing {@link Edges}.
      */
     private static void registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Edges.class);
+        Registration r = new Registration(plugins, Edges.class);
         for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
             r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) {
@@ -445,9 +443,8 @@
             return true;
         }
 
-        void register(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
-            plugins.register(method, this);
+        void register(InvocationPlugins plugins) {
+            plugins.register(this, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
         }
     }
 
@@ -473,10 +470,9 @@
             return true;
         }
 
-        void register(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        void register(InvocationPlugins plugins) {
             String name = kind.toJavaClass().getSimpleName() + "Value";
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
-            plugins.register(method, this);
+            plugins.register(this, kind.toBoxedJavaClass(), name, Receiver.class);
         }
     }
 
@@ -536,8 +532,8 @@
         }
     }
 
-    private static void registerGraalDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, GraalDirectives.class);
+    private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, GraalDirectives.class);
         r.register0("deoptimize", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
                 b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
@@ -596,7 +592,7 @@
         }
     }
 
-    private static void registerJMHBlackholePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    private static void registerJMHBlackholePlugins(InvocationPlugins plugins) {
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode blackhole, ValueNode value) {
                 b.append(new BlackholeNode(value));
@@ -608,7 +604,7 @@
             Class<?> blackholeClass;
             blackholeClass = ReplacementsImpl.resolveClass(name, true);
             if (blackholeClass != null) {
-                Registration r = new Registration(plugins, metaAccess, blackholeClass);
+                Registration r = new Registration(plugins, blackholeClass);
                 for (Kind kind : Kind.values()) {
                     if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) {
                         Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Tue Mar 17 11:23:06 2015 -0700
@@ -32,8 +32,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Mar 17 11:23:06 2015 -0700
@@ -37,12 +37,14 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
@@ -56,7 +58,6 @@
 import com.oracle.graal.printer.*;
 import com.oracle.graal.runtime.*;
 import com.oracle.graal.truffle.*;
-import com.oracle.graal.word.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -78,6 +79,7 @@
     private final ThreadPoolExecutor compileQueue;
 
     private final Map<RootCallTarget, Void> callTargets = Collections.synchronizedMap(new WeakHashMap<RootCallTarget, Void>());
+    private static final long THREAD_EETOP_OFFSET = eetopOffset();
 
     private HotSpotTruffleRuntime() {
         installOptimizedCallTargetCallMethod();
@@ -185,14 +187,18 @@
     }
 
     private static CompilationResult compileMethod(ResolvedJavaMethod javaMethod) {
-        Providers providers = getGraalProviders();
-        MetaAccessProvider metaAccess = providers.getMetaAccess();
-        SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
+        HotSpotProviders providers = getGraalProviders();
+        SuitesProvider suitesProvider = providers.getSuites();
         Suites suites = suitesProvider.createSuites();
         LIRSuites lirSuites = suitesProvider.createLIRSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod, AllowAssumptions.NO);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL, null).apply(graph);
+
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(plugins);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.ALL, null).apply(graph);
+
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
@@ -201,9 +207,9 @@
                         suites, lirSuites, new CompilationResult(), factory);
     }
 
-    private static Providers getGraalProviders() {
+    private static HotSpotProviders getGraalProviders() {
         RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class);
-        return runtimeProvider.getHostBackend().getProviders();
+        return (HotSpotProviders) runtimeProvider.getHostBackend().getProviders();
     }
 
     private static PhaseSuite<HighTierContext> getGraphBuilderSuite(SuitesProvider suitesProvider) {
@@ -242,7 +248,7 @@
             try {
                 future.get();
             } catch (ExecutionException e) {
-                if (TruffleCompilationExceptionsAreThrown.getValue() && !(e.getCause() instanceof BailoutException) && !((BailoutException) e.getCause()).isPermanent()) {
+                if (TruffleCompilationExceptionsAreThrown.getValue() && !(e.getCause() instanceof BailoutException && !((BailoutException) e.getCause()).isPermanent())) {
                     throw new RuntimeException(e.getCause());
                 } else {
                     // silently ignored
@@ -315,10 +321,11 @@
     public void notifyTransferToInterpreter() {
         CompilerAsserts.neverPartOfCompilation();
         if (TraceTruffleTransferToInterpreter.getValue()) {
-            Word thread = CurrentJavaThreadNode.get();
-            boolean deoptimized = thread.readByte(HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset) != 0;
+            long thread = UnsafeAccess.unsafe.getLong(Thread.currentThread(), THREAD_EETOP_OFFSET);
+            long pendingTransferToInterpreterAddress = thread + HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset;
+            boolean deoptimized = UnsafeAccess.unsafe.getByte(pendingTransferToInterpreterAddress) != 0;
             if (deoptimized) {
-                thread.writeByte(HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset, (byte) 0);
+                UnsafeAccess.unsafe.putByte(pendingTransferToInterpreterAddress, (byte) 0);
 
                 logTransferToInterpreter();
             }
@@ -332,4 +339,12 @@
         String suffix = stackTrace.length > skip + limit ? "\n  ..." : "";
         TTY.out().out().println(Arrays.stream(stackTrace).skip(skip).limit(limit).map(StackTraceElement::toString).collect(Collectors.joining("\n  ", "", suffix)));
     }
+
+    private static long eetopOffset() {
+        try {
+            return UnsafeAccess.unsafe.objectFieldOffset(Thread.class.getDeclaredField("eetop"));
+        } catch (Exception e) {
+            throw new GraalInternalError(e);
+        }
+    }
 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -25,16 +25,16 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.java.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.truffle.substitutions.*;
 import com.oracle.truffle.api.*;
 
 public class ExactMathTest extends GraalCompilerTest {
 
     @Override
-    protected void editGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
-        TruffleGraphBuilderPlugins.registerExactMathPlugins(getMetaAccess(), plugins.getInvocationPlugins());
-        super.editGraphBuilderPlugins(plugins);
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        TruffleGraphBuilderPlugins.registerExactMathPlugins(conf.getPlugins().getInvocationPlugins());
+        return super.editGraphBuilderConfiguration(conf);
     }
 
     @Test
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SimplePartialEvaluationTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SimplePartialEvaluationTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -136,4 +136,11 @@
         assertPartialEvalNoInvokes(rootNode);
         assertPartialEvalEquals("constant42", rootNode);
     }
+
+    @Test
+    public void lambda() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new LambdaTestNode();
+        assertPartialEvalEquals("constant42", new RootTestNode(fd, "constantValue", result));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LambdaTestNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -0,0 +1,38 @@
+/*
+ * 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.truffle.test.nodes;
+
+import java.util.function.*;
+
+import com.oracle.truffle.api.frame.*;
+
+public class LambdaTestNode extends AbstractTestNode {
+    @Override
+    public int execute(VirtualFrame frame) {
+        return lambda(() -> 42);
+    }
+
+    private static int lambda(Supplier<Integer> supplier) {
+        return supplier.get();
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Mar 17 11:23:06 2015 -0700
@@ -28,7 +28,9 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -38,10 +40,9 @@
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
-import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
@@ -49,6 +50,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
@@ -63,7 +65,6 @@
 import com.oracle.graal.truffle.nodes.frame.*;
 import com.oracle.graal.truffle.nodes.frame.NewFrameNode.VirtualOnlyInstanceNode;
 import com.oracle.graal.truffle.phases.*;
-import com.oracle.graal.truffle.substitutions.*;
 import com.oracle.graal.virtual.phases.ea.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -185,14 +186,14 @@
         }
     }
 
-    private class InlineInvokePlugin implements GraphBuilderPlugin.InlineInvokePlugin {
+    private class PEInlineInvokePlugin implements InlineInvokePlugin {
 
-        private Stack<TruffleInlining> inlining;
+        private Deque<TruffleInlining> inlining;
         private OptimizedDirectCallNode lastDirectCallNode;
         private final Replacements replacements;
 
-        public InlineInvokePlugin(TruffleInlining inlining, Replacements replacements) {
-            this.inlining = new Stack<>();
+        public PEInlineInvokePlugin(TruffleInlining inlining, Replacements replacements) {
+            this.inlining = new ArrayDeque<>();
             this.inlining.push(inlining);
             this.replacements = replacements;
         }
@@ -201,28 +202,37 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
+            IntrinsicMethod intrinsicMethod = builder.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(original);
+            if (intrinsicMethod != null) {
+                InlineInfo inlineInfo = getMethodHandleIntrinsicInlineInfo(builder, arguments, intrinsicMethod);
+                if (inlineInfo != null) {
+                    return inlineInfo;
+                }
+            }
             if (replacements != null && (replacements.getMethodSubstitutionMethod(original) != null || replacements.getMacroSubstitution(original) != null)) {
                 return null;
             }
             assert !builder.parsingReplacement();
-            if (original.equals(callSiteProxyMethod)) {
-                ValueNode arg1 = arguments[0];
-                if (!arg1.isConstant()) {
-                    GraalInternalError.shouldNotReachHere("The direct call node does not resolve to a constant!");
-                }
+            if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
+                if (original.equals(callSiteProxyMethod)) {
+                    ValueNode arg1 = arguments[0];
+                    if (!arg1.isConstant()) {
+                        GraalInternalError.shouldNotReachHere("The direct call node does not resolve to a constant!");
+                    }
 
-                Object callNode = builder.getSnippetReflection().asObject(Object.class, (JavaConstant) arg1.asConstant());
-                if (callNode instanceof OptimizedDirectCallNode) {
-                    OptimizedDirectCallNode directCallNode = (OptimizedDirectCallNode) callNode;
-                    lastDirectCallNode = directCallNode;
-                }
-            } else if (original.equals(callDirectMethod)) {
-                TruffleInliningDecision decision = getDecision(inlining.peek(), lastDirectCallNode);
-                lastDirectCallNode = null;
-                if (decision != null && decision.isInline()) {
-                    inlining.push(decision);
-                    builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
-                    return new InlineInfo(callInlinedMethod, false, false);
+                    Object callNode = builder.getSnippetReflection().asObject(Object.class, (JavaConstant) arg1.asConstant());
+                    if (callNode instanceof OptimizedDirectCallNode) {
+                        OptimizedDirectCallNode directCallNode = (OptimizedDirectCallNode) callNode;
+                        lastDirectCallNode = directCallNode;
+                    }
+                } else if (original.equals(callDirectMethod)) {
+                    TruffleInliningDecision decision = getDecision(inlining.peek(), lastDirectCallNode);
+                    lastDirectCallNode = null;
+                    if (decision != null && decision.isInline()) {
+                        inlining.push(decision);
+                        builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
+                        return new InlineInfo(callInlinedMethod, false, false);
+                    }
                 }
             }
             return new InlineInfo(original, false, false);
@@ -233,9 +243,59 @@
                 inlining.pop();
             }
         }
+
+        private InlineInfo getMethodHandleIntrinsicInlineInfo(GraphBuilderContext builder, ValueNode[] arguments, IntrinsicMethod intrinsicMethod) {
+            ResolvedJavaMethod targetMethod = null;
+            switch (intrinsicMethod) {
+                case INVOKE_BASIC:
+                    ValueNode methodHandleNode = arguments[0];
+                    if (methodHandleNode.isConstant()) {
+                        targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true);
+                    }
+                    break;
+                case LINK_TO_STATIC:
+                case LINK_TO_SPECIAL:
+                case LINK_TO_VIRTUAL:
+                case LINK_TO_INTERFACE:
+                    ValueNode memberNameNode = arguments[arguments.length - 1];
+                    if (memberNameNode.isConstant()) {
+                        targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant());
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+            if (targetMethod != null) {
+                // TODO maybe cast arguments
+
+                if (targetMethod.canBeStaticallyBound()) {
+                    return new InlineInfo(targetMethod, false, false);
+                }
+
+                // Try to get the most accurate receiver type
+                if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+                    ResolvedJavaType receiverType = StampTool.typeOrNull(arguments[0].stamp());
+                    if (receiverType != null) {
+                        AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+                        if (concreteMethod != null) {
+                            builder.getAssumptions().record(concreteMethod);
+                            return new InlineInfo(concreteMethod.getResult(), false, false);
+                        }
+                    }
+                } else {
+                    AssumptionResult<ResolvedJavaMethod> concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
+                    if (concreteMethod != null) {
+                        builder.getAssumptions().record(concreteMethod);
+                        return new InlineInfo(concreteMethod.getResult(), false, false);
+                    }
+                }
+            }
+
+            return null;
+        }
     }
 
-    private class LoopExplosionPlugin implements GraphBuilderPlugin.LoopExplosionPlugin {
+    private class PELoopExplosionPlugin implements LoopExplosionPlugin {
 
         public boolean shouldExplodeLoops(ResolvedJavaMethod method) {
             return method.getAnnotation(ExplodeLoop.class) != null;
@@ -259,10 +319,9 @@
         plugins.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
         plugins.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
         callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-        plugins.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
-        plugins.setLoopExplosionPlugin(new LoopExplosionPlugin());
-        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getPlugins().getInvocationPlugins());
-
+        plugins.setInlineInvokePlugin(new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
+        plugins.setLoopExplosionPlugin(new PELoopExplosionPlugin());
+        InvocationPlugins invocationPlugins = newConfig.getPlugins().getInvocationPlugins();
         new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig,
                         TruffleCompilerImpl.Optimizations, null).apply(graph);
         Debug.dump(graph, "After FastPE");
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Mar 17 11:23:06 2015 -0700
@@ -32,6 +32,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Mar 17 11:23:06 2015 -0700
@@ -27,15 +27,17 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
@@ -48,6 +50,7 @@
 import com.oracle.graal.printer.*;
 import com.oracle.graal.runtime.*;
 import com.oracle.graal.truffle.nodes.*;
+import com.oracle.graal.truffle.substitutions.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -97,14 +100,20 @@
         this.lirSuites = backend.getSuites().getDefaultLIRSuites();
 
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
-        GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
 
-        this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
+        Plugins plugins;
         if (TruffleCompilerOptions.FastPE.getValue()) {
             GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-            this.config.getPlugins().getInvocationPlugins().setDefaults(phase.getGraphBuilderConfig().getPlugins().getInvocationPlugins());
+            InvocationPlugins invocationPlugins = new InvocationPlugins(phase.getGraphBuilderConfig().getPlugins().getInvocationPlugins());
+            plugins = new Plugins(invocationPlugins);
+            TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), invocationPlugins);
+        } else {
+            plugins = new Plugins(new InvocationPlugins(backendProviders.getMetaAccess()));
         }
 
+        this.config = GraphBuilderConfiguration.getDefault(plugins).withSkippedExceptionTypes(skippedExceptionTypes);
+
+        GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault(plugins).withSkippedExceptionTypes(skippedExceptionTypes);
         this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, TruffleCompilerImpl.Optimizations);
 
         this.partialEvaluator = new PartialEvaluator(providers, config, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Tue Mar 17 11:23:06 2015 -0700
@@ -31,10 +31,8 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.java.InvocationPlugins.Registration;
-import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -53,22 +51,22 @@
 public class TruffleGraphBuilderPlugins {
     public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
 
-        registerOptimizedAssumptionPlugins(metaAccess, plugins);
-        registerExactMathPlugins(metaAccess, plugins);
-        registerCompilerDirectivesPlugins(metaAccess, plugins);
+        registerOptimizedAssumptionPlugins(plugins);
+        registerExactMathPlugins(plugins);
+        registerCompilerDirectivesPlugins(plugins);
         registerOptimizedCallTargetPlugins(metaAccess, plugins);
-        registerUnsafeAccessImplPlugins(metaAccess, plugins);
+        registerUnsafeAccessImplPlugins(plugins);
 
         if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
-            registerFrameWithoutBoxingPlugins(metaAccess, plugins);
+            registerFrameWithoutBoxingPlugins(plugins);
         } else {
-            registerFrameWithBoxingPlugins(metaAccess, plugins);
+            registerFrameWithBoxingPlugins(plugins);
         }
 
     }
 
-    public static void registerOptimizedAssumptionPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, OptimizedAssumption.class);
+    public static void registerOptimizedAssumptionPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, OptimizedAssumption.class);
         r.register1("isValid", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
                 if (arg.isConstant()) {
@@ -86,8 +84,8 @@
         });
     }
 
-    public static void registerExactMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, ExactMath.class);
+    public static void registerExactMathPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, ExactMath.class);
         for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) {
             Class<?> type = kind.toJavaClass();
             r.register2("addExact", type, type, new InvocationPlugin() {
@@ -123,8 +121,8 @@
         }
     }
 
-    public static void registerCompilerDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class);
+    public static void registerCompilerDirectivesPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, CompilerDirectives.class);
         r.register0("inInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
                 b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(false)));
@@ -190,7 +188,7 @@
             }
         });
 
-        r = new Registration(plugins, metaAccess, CompilerAsserts.class);
+        r = new Registration(plugins, CompilerAsserts.class);
         r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 ValueNode curValue = value;
@@ -229,7 +227,7 @@
     }
 
     public static void registerOptimizedCallTargetPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, OptimizedCallTarget.class);
+        Registration r = new Registration(plugins, OptimizedCallTarget.class);
         r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode descriptor, ValueNode args) {
                 Class<?> frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class;
@@ -245,21 +243,21 @@
         });
     }
 
-    public static void registerFrameWithoutBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, FrameWithoutBoxing.class);
+    public static void registerFrameWithoutBoxingPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, FrameWithoutBoxing.class);
         registerMaterialize(r);
         registerUnsafeCast(r);
         registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
     }
 
-    public static void registerFrameWithBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, FrameWithBoxing.class);
+    public static void registerFrameWithBoxingPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, FrameWithBoxing.class);
         registerMaterialize(r);
         registerUnsafeCast(r);
     }
 
-    public static void registerUnsafeAccessImplPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
+    public static void registerUnsafeAccessImplPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, UnsafeAccessImpl.class);
         registerUnsafeCast(r);
         registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
     }
@@ -267,7 +265,7 @@
     private static void registerMaterialize(Registration r) {
         r.register1("materialize", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode frame) {
-                b.push(Kind.Object, b.append(new MaterializeFrameNode(frame)));
+                b.push(Kind.Object, b.append(new MaterializeFrameNode(GraphBuilderContext.nullCheckedValue(b, frame))));
                 return true;
             }
         });
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Tue Mar 17 11:23:06 2015 -0700
@@ -380,11 +380,7 @@
 
         @Override
         public Probe getProbe() {
-            try {
-                return probeNode.getProbe();
-            } catch (IllegalStateException e) {
-                throw new IllegalStateException("Cannot call getProbe() on a wrapper that has no probe");
-            }
+            return probeNode.getProbe();
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java	Tue Mar 17 11:23:06 2015 -0700
@@ -119,11 +119,7 @@
 
         @Override
         public Probe getProbe() {
-            try {
-                return probeNode.getProbe();
-            } catch (IllegalStateException e) {
-                throw new IllegalStateException("Cannot call getProbe() on a wrapper that has no probe");
-            }
+            return probeNode.getProbe();
         }
 
         @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java	Tue Mar 17 11:23:06 2015 -0700
@@ -58,12 +58,7 @@
         /**
          * Wrapper not assignable to the parent's child field.
          */
-        WRAPPER_TYPE("Wrapper not assignable to parent's child field"),
-
-        /**
-         * Attempt to \"probe lite\" an already probed node.
-         */
-        LITE_VIOLATION("Attempt to \"probe lite\" an already probed node");
+        WRAPPER_TYPE("Wrapper not assignable to parent's child field");
 
         final String message;
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -33,9 +33,20 @@
 import com.oracle.truffle.api.source.*;
 
 /**
- * Implementation interfaces and classes for attaching {@link Probe}s to {@link WrapperNode}s.
+ * Implementation class & interface for enabling the attachment of {@linkplain Probe Probes} to
+ * Truffle ASTs.
+ * <p>
+ * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain Instrument
+ * instruments}. It is attached to an AST as a child of a guest-language-specific
+ * {@link WrapperNode} node.
+ * <p>
+ * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments}
+ * will be cloned along with the {@link WrapperNode} to which it is attached. An instance of
+ * {@link Probe} represents abstractly the instrumentation at a particular location in a GL AST,
+ * tracks the clones of the chain, and keeps the instrumentation attached to the clones consistent.
  */
-public abstract class ProbeNode extends Node implements TruffleEvents, InstrumentationNode {
+@NodeInfo(cost = NodeCost.NONE)
+public final class ProbeNode extends Node implements TruffleEvents, InstrumentationNode {
 
     /**
      * A node that can be inserted into a Truffle AST, and which enables {@linkplain Instrument
@@ -91,8 +102,7 @@
         Node getChild();
 
         /**
-         * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper
-         * installed via {@linkplain Node#probeLite(ASTInstrumentListener) "lite-Probing"}.
+         * Gets the {@link Probe} responsible for installing this wrapper.
          */
         Probe getProbe();
 
@@ -100,7 +110,6 @@
          * Implementation support for completing a newly created wrapper node.
          */
         void insertProbe(ProbeNode probeNode);
-
     }
 
     /**
@@ -109,202 +118,99 @@
      */
     public static Probe insertProbe(WrapperNode wrapper) {
         final SourceSection sourceSection = wrapper.getChild().getSourceSection();
-        final ProbeFullNode probeFullNode = new ProbeFullNode(); // private constructor
-        final Probe probe = new Probe(probeFullNode, sourceSection);  // package private access
-        probeFullNode.setProbe(probe);
-        wrapper.insertProbe(probeFullNode);
-        return probe;
+        final ProbeNode probeNode = new ProbeNode(); // private constructor
+        probeNode.probe = new Probe(probeNode, sourceSection);  // package private access
+        wrapper.insertProbe(probeNode);
+        return probeNode.probe;
     }
 
+    // Never changed once set.
+    @CompilationFinal Probe probe = null;
     /**
-     * Creates a new {@link ProbeLiteNode} associated with, and attached to, a Guest Language
-     * specific instance of {@link WrapperNode}.
+     * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in chain.
      */
-    public static void insertProbeLite(WrapperNode wrapper, ASTInstrumentListener instrumentListener) {
-        final ProbeLiteNode probeLiteNode = new ProbeLiteNode(instrumentListener);
-        wrapper.insertProbe(probeLiteNode);
-    }
+    @Child protected AbstractInstrumentNode firstInstrument;
 
     @Override
     public boolean isInstrumentable() {
         return false;
     }
 
+    @Override
+    public Node copy() {
+        Node node = super.copy();
+        probe.registerProbeNodeClone((ProbeNode) node);
+        return node;
+    }
+
     /**
      * @return the {@link Probe} permanently associated with this {@link ProbeNode}.
-     *
-     * @throws IllegalStateException if this location was "lite-Probed"
      */
-    public abstract Probe getProbe() throws IllegalStateException;
+    public Probe getProbe() {
+        return probe;
+    }
+
+    public void enter(Node node, VirtualFrame vFrame) {
+        this.probe.checkProbeUnchanged();
+        final SyntaxTagTrap trap = probe.getTrap();
+        if (trap != null) {
+            trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize());
+        }
+        if (firstInstrument != null) {
+            firstInstrument.enter(node, vFrame);
+        }
+    }
+
+    public void returnVoid(Node node, VirtualFrame vFrame) {
+        this.probe.checkProbeUnchanged();
+        if (firstInstrument != null) {
+            firstInstrument.returnVoid(node, vFrame);
+        }
+    }
+
+    public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+        this.probe.checkProbeUnchanged();
+        if (firstInstrument != null) {
+            firstInstrument.returnValue(node, vFrame, result);
+        }
+    }
+
+    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+        this.probe.checkProbeUnchanged();
+        if (firstInstrument != null) {
+            firstInstrument.returnExceptional(node, vFrame, exception);
+        }
+    }
+
+    public String instrumentationInfo() {
+        return "Standard probe";
+    }
 
     /**
      * Adds an {@link AbstractInstrumentNode} to this chain.
-     *
-     * @throws IllegalStateException if at a "lite-Probed" location.
      */
-    abstract void addInstrument(Instrument instrument);
+    @TruffleBoundary
+    void addInstrument(Instrument instrument) {
+        assert instrument.getProbe() == probe;
+        // The existing chain of nodes may be empty
+        // Attach the modified chain.
+        firstInstrument = insert(instrument.addToChain(firstInstrument));
+    }
 
     /**
      * Removes an instrument from this chain of instruments.
      *
-     * @throws IllegalStateException if at a "lite-Probed" location.
      * @throws RuntimeException if no matching instrument is found,
      */
-    abstract void removeInstrument(Instrument instrument);
-
-    /**
-     * Implementation class & interfaces for enabling the attachment of {@linkplain Probe Probes} to
-     * Truffle ASTs.
-     * <p>
-     * Head of a chain of nodes acting on behalf of {@linkplain Instrument instruments}, attached to
-     * a Guest Language (GL) AST as a child of a GL-specific {@link WrapperNode} node.
-     * <p>
-     * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument
-     * instruments} will be cloned along with the {@link WrapperNode} to which it is attached. An
-     * instance of {@link Probe} represents abstractly the instrumentation at a particular location
-     * in a GL AST, tracks the clones of the chain, and keeps the instrumentation attached to the
-     * clones consistent.
-     */
-    @NodeInfo(cost = NodeCost.NONE)
-    private static final class ProbeFullNode extends ProbeNode {
-
-        /**
-         * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in
-         * chain.
-         */
-        @Child protected AbstractInstrumentNode firstInstrument;
-
-        // Never changed once set.
-        @CompilationFinal private Probe probe = null;
-
-        private ProbeFullNode() {
-            this.firstInstrument = null;
-        }
-
-        @Override
-        public Probe getProbe() throws IllegalStateException {
-            return probe;
-        }
-
-        @Override
-        public Node copy() {
-            Node node = super.copy();
-            probe.registerProbeNodeClone((ProbeNode) node);
-            return node;
-        }
-
-        private void setProbe(Probe probe) {
-            this.probe = probe;
-        }
-
-        @Override
-        @TruffleBoundary
-        void addInstrument(Instrument instrument) {
-            assert instrument.getProbe() == probe;
-            // The existing chain of nodes may be empty
-            // Attach the modified chain.
-            firstInstrument = insert(instrument.addToChain(firstInstrument));
-        }
-
-        @Override
-        @TruffleBoundary
-        void removeInstrument(Instrument instrument) {
-            assert instrument.getProbe() == probe;
-            final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument);
-            if (modifiedChain == null) {
-                firstInstrument = null;
-            } else {
-                firstInstrument = insert(modifiedChain);
-            }
-        }
-
-        public void enter(Node node, VirtualFrame vFrame) {
-            this.probe.checkProbeUnchanged();
-            final SyntaxTagTrap trap = probe.getTrap();
-            if (trap != null) {
-                trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize());
-            }
-            if (firstInstrument != null) {
-                firstInstrument.enter(node, vFrame);
-            }
-        }
-
-        public void returnVoid(Node node, VirtualFrame vFrame) {
-            this.probe.checkProbeUnchanged();
-            if (firstInstrument != null) {
-                firstInstrument.returnVoid(node, vFrame);
-            }
-        }
-
-        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-            this.probe.checkProbeUnchanged();
-            if (firstInstrument != null) {
-                firstInstrument.returnValue(node, vFrame, result);
-            }
-        }
-
-        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-            this.probe.checkProbeUnchanged();
-            if (firstInstrument != null) {
-                firstInstrument.returnExceptional(node, vFrame, exception);
-            }
-        }
-
-        public String instrumentationInfo() {
-            return "Standard probe";
+    @TruffleBoundary
+    void removeInstrument(Instrument instrument) {
+        assert instrument.getProbe() == probe;
+        final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument);
+        if (modifiedChain == null) {
+            firstInstrument = null;
+        } else {
+            firstInstrument = insert(modifiedChain);
         }
     }
 
-    /**
-     * Implementation of a probe that only ever has a single "instrument" associated with it. No
-     * {@link Instrument} is ever created; instead this method simply delegates the various enter
-     * and return events to a {@link TruffleEvents} passed in during construction.
-     */
-    @NodeInfo(cost = NodeCost.NONE)
-    private static final class ProbeLiteNode extends ProbeNode {
-
-        private final ASTInstrumentListener instrumentListener;
-
-        private ProbeLiteNode(ASTInstrumentListener eventListener) {
-            this.instrumentListener = eventListener;
-        }
-
-        @Override
-        public Probe getProbe() throws IllegalStateException {
-            throw new IllegalStateException("\"lite-Probed\" nodes have no explicit Probe");
-        }
-
-        @Override
-        @TruffleBoundary
-        void addInstrument(Instrument instrument) {
-            throw new IllegalStateException("Instruments may not be added at a \"lite-probed\" location");
-        }
-
-        @Override
-        @TruffleBoundary
-        void removeInstrument(Instrument instrument) {
-            throw new IllegalStateException("Instruments may not be removed at a \"lite-probed\" location");
-        }
-
-        public void enter(Node node, VirtualFrame vFrame) {
-            instrumentListener.enter(getProbe(), node, vFrame);
-        }
-
-        public void returnVoid(Node node, VirtualFrame vFrame) {
-            instrumentListener.returnVoid(getProbe(), node, vFrame);
-        }
-
-        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-            instrumentListener.returnValue(getProbe(), node, vFrame, result);
-        }
-
-        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-            instrumentListener.returnExceptional(getProbe(), node, vFrame, exception);
-        }
-
-        public String instrumentationInfo() {
-            return "\"Lite\" probe";
-        }
-
-    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Mar 17 11:23:06 2015 -0700
@@ -497,61 +497,6 @@
     }
 
     /**
-     * Enables "one-shot", unmodifiable {@linkplain Instrument instrumentation} of a node, where the
-     * node is presumed to be part of a well-formed Truffle AST that is not being executed.
-     * <p>
-     * Modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between the node and
-     * its parent; the wrapper node must be provided by implementations of
-     * {@link #createWrapperNode()}.
-     * <p>
-     * Unlike {@link #probe()}, once {@link #probeLite(ASTInstrumentListener)} is called at a node,
-     * no additional probing can be added and no additional instrumentation can be attached.
-     * <p>
-     * This restricted form of instrumentation is intended for special cases where only one kind of
-     * instrumentation is desired, and for which performance is a concern
-     *
-     * @param instrumentListener
-     * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged
-     */
-    public final void probeLite(ASTInstrumentListener instrumentListener) {
-
-        if (this instanceof WrapperNode) {
-            throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null);
-        }
-
-        if (parent == null) {
-            throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, this, null);
-        }
-
-        if (parent instanceof WrapperNode) {
-            throw new ProbeException(ProbeFailure.Reason.LITE_VIOLATION, null, this, null);
-        }
-
-        if (!isInstrumentable()) {
-            throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, this, null);
-        }
-
-        // Create a new wrapper/probe with this node as its child.
-        final WrapperNode wrapper = createWrapperNode();
-
-        if (wrapper == null || !(wrapper instanceof Node)) {
-            throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, this, wrapper);
-        }
-
-        final Node wrapperNode = (Node) wrapper;
-
-        if (!this.isSafelyReplaceableBy(wrapperNode)) {
-            throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, this, wrapper);
-        }
-
-        // Connect it to a Probe
-        ProbeNode.insertProbeLite(wrapper, instrumentListener);
-
-        // Replace this node in the AST with the wrapper
-        this.replace(wrapperNode);
-    }
-
-    /**
      * Converts this node to a textual representation useful for debugging.
      */
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -72,11 +72,7 @@
     }
 
     public Probe getProbe() {
-        try {
-            return probeNode.getProbe();
-        } catch (IllegalStateException e) {
-            throw new IllegalStateException("A lite-Probed wrapper has no explicit Probe");
-        }
+        return probeNode.getProbe();
     }
 
     public Node getChild() {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Tue Mar 17 11:22:56 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Tue Mar 17 11:23:06 2015 -0700
@@ -65,11 +65,7 @@
     }
 
     public Probe getProbe() {
-        try {
-            return probeNode.getProbe();
-        } catch (IllegalStateException e) {
-            throw new IllegalStateException("A lite-Probed wrapper has no explicit Probe");
-        }
+        return probeNode.getProbe();
     }
 
     @Override
--- a/mx/suite.py	Tue Mar 17 11:22:56 2015 -0700
+++ b/mx/suite.py	Tue Mar 17 11:23:06 2015 -0700
@@ -803,6 +803,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.phases",
+        "com.oracle.graal.graphbuilderconf"
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "annotationProcessors" : ["com.oracle.graal.service.processor"],
@@ -810,6 +811,17 @@
       "workingSets" : "Graal,Java",
     },
 
+    "com.oracle.graal.graphbuilderconf" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.nodes",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Java",
+    },
+
     "com.oracle.graal.compiler.common" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Tue Mar 17 11:22:56 2015 -0700
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Tue Mar 17 11:23:06 2015 -0700
@@ -715,7 +715,7 @@
                                     int total_args_passed,
                                     int comp_args_on_stack,
                                     const BasicType *sig_bt,
-                                    const VMRegPair *regs
+                                    const VMRegPair *regs,
                                     int frame_extension_argument) {
   assert(frame_extension_argument == -1, "unsupported");
 
--- a/src/os/solaris/vm/os_solaris.cpp	Tue Mar 17 11:22:56 2015 -0700
+++ b/src/os/solaris/vm/os_solaris.cpp	Tue Mar 17 11:23:06 2015 -0700
@@ -2674,8 +2674,6 @@
 
   if (!recoverable_mmap_error(err)) {
     warn_fail_commit_memory(addr, bytes, exec, err);
-    // Introduced temporarily to debug the memory allocation issues on Solaris
-    tty->print_cr("GRAAL_DEBUG: unrecoverable error during mmap got errno %d", err);
     vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory.");
   }
 
--- a/src/share/vm/compiler/compileBroker.cpp	Tue Mar 17 11:22:56 2015 -0700
+++ b/src/share/vm/compiler/compileBroker.cpp	Tue Mar 17 11:23:06 2015 -0700
@@ -801,12 +801,6 @@
   GraalCompiler* graal = new GraalCompiler();
 #endif
 
-#ifdef COMPILER1
-  if (c1_count > 0) {
-    _compilers[0] = new Compiler();
-  }
-#endif // COMPILER1
-
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
   if (FLAG_IS_DEFAULT(GraalThreads)) {
@@ -817,8 +811,18 @@
   } else {
     c2_count = GraalThreads;
   }
+  if (FLAG_IS_DEFAULT(GraalHostThreads)) {
+  } else {
+    c1_count = GraalHostThreads;
+  }
 #endif // COMPILERGRAAL
 
+#ifdef COMPILER1
+  if (c1_count > 0) {
+    _compilers[0] = new Compiler();
+  }
+#endif // COMPILER1
+
 #ifdef COMPILER2
   if (c2_count > 0) {
     _compilers[1] = new C2Compiler();
--- a/src/share/vm/graal/graalGlobals.hpp	Tue Mar 17 11:22:56 2015 -0700
+++ b/src/share/vm/graal/graalGlobals.hpp	Tue Mar 17 11:23:06 2015 -0700
@@ -61,6 +61,9 @@
   COMPILERGRAAL_PRESENT(product(intx, GraalThreads, 1,                      \
           "Force number of Graal compiler threads to use"))                 \
                                                                             \
+  COMPILERGRAAL_PRESENT(product(intx, GraalHostThreads, 1,                  \
+          "Force number of compiler threads for Graal host compiler"))      \
+                                                                            \
   GRAAL_ONLY(product(bool, CodeInstallSafepointChecks, true,                \
           "Perform explicit safepoint checks while installing code"))       \
                                                                             \
--- a/test/blacklist_sparc.txt	Tue Mar 17 11:22:56 2015 -0700
+++ b/test/blacklist_sparc.txt	Tue Mar 17 11:23:06 2015 -0700
@@ -1,2 +1,3 @@
 com.oracle.graal.replacements.test.StandardMethodSubstitutionsTest
 com.oracle.graal.hotspot.amd64.test.CompressedNullCheckTest
+com.oracle.nfi.test.NativeFunctionInterfaceTest