changeset 19124:a5f47cb74b1b

Merge.
author Josef Eisl <josef.eisl@jku.at>
date Wed, 04 Feb 2015 13:51:17 +0100
parents 0f3c0639dc3f (current diff) 036c0b9bd4f5 (diff)
children e4fda434ba74
files graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java
diffstat 45 files changed, 1093 insertions(+), 484 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Wed Feb 04 13:51:17 2015 +0100
@@ -0,0 +1,206 @@
+/*
+ * 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.api.directives.test;
+
+import java.lang.annotation.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
+
+public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    @Repeatable(AnchorSnippet.class)
+    private @interface NodeCount {
+
+        Class<? extends Node> nodeClass();
+
+        int expectedCount();
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    private @interface AnchorSnippet {
+        NodeCount[] value();
+    }
+
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
+    public static int verifyMergeSnippet(int arg) {
+        if (arg > 5) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2)
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
+    public static int preventMergeSnippet(int arg) {
+        if (arg > 5) {
+            GraalDirectives.controlFlowAnchor();
+            return 1;
+        } else {
+            GraalDirectives.controlFlowAnchor();
+            return 2;
+        }
+    }
+
+    @Test
+    public void testMerge() {
+        test("verifyMergeSnippet", 42);
+        test("preventMergeSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
+    public static int verifyDuplicateSnippet(int arg) {
+        int ret;
+        if (arg > 5) {
+            ret = 17;
+        } else {
+            ret = arg;
+        }
+        return 42 / ret;
+    }
+
+    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
+    public static int preventDuplicateSnippet(int arg) {
+        int ret;
+        if (arg > 5) {
+            ret = 17;
+        } else {
+            ret = arg;
+        }
+        GraalDirectives.controlFlowAnchor();
+        return 42 / ret;
+    }
+
+    @Test
+    public void testDuplicate() {
+        test("verifyDuplicateSnippet", 42);
+        test("preventDuplicateSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0)
+    public static int verifyFullUnrollSnippet(int arg) {
+        int ret = arg;
+        for (int i = 0; i < 5; i++) {
+            ret = ret * 3 + 1;
+        }
+        return ret;
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
+    public static int preventFullUnrollSnippet(int arg) {
+        int ret = arg;
+        for (int i = 0; i < 5; i++) {
+            GraalDirectives.controlFlowAnchor();
+            ret = ret * 3 + 1;
+        }
+        return ret;
+    }
+
+    @Test
+    public void testFullUnroll() {
+        test("verifyFullUnrollSnippet", 42);
+        test("preventFullUnrollSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = IfNode.class, expectedCount = 4)
+    public static void verifyPeelSnippet(int arg) {
+        int ret = arg;
+        while (ret > 1) {
+            if (ret % 2 == 0) {
+                ret /= 2;
+            } else {
+                ret = 3 * ret + 1;
+            }
+        }
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = IfNode.class, expectedCount = 2)
+    public static void preventPeelSnippet(int arg) {
+        int ret = arg;
+        while (ret > 1) {
+            GraalDirectives.controlFlowAnchor();
+            if (ret % 2 == 0) {
+                ret /= 2;
+            } else {
+                ret = 3 * ret + 1;
+            }
+        }
+    }
+
+    @Test
+    public void testPeel() {
+        test("verifyPeelSnippet", 42);
+        test("preventPeelSnippet", 42);
+    }
+
+    private static List<NodeCount> getNodeCountAnnotations(StructuredGraph graph) {
+        ResolvedJavaMethod method = graph.method();
+        AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class);
+        if (snippet != null) {
+            return Arrays.asList(snippet.value());
+        }
+
+        NodeCount single = method.getAnnotation(NodeCount.class);
+        if (single != null) {
+            return Collections.singletonList(single);
+        }
+
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();
+        for (int i = 0; i < anchors.size(); i++) {
+            ControlFlowAnchorNode a = anchors.get(i);
+            for (int j = i + 1; j < anchors.size(); j++) {
+                ControlFlowAnchorNode b = anchors.get(j);
+                if (a.valueEquals(b)) {
+                    Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")");
+                }
+            }
+        }
+
+        for (NodeCount nodeCount : getNodeCountAnnotations(graph)) {
+            NodeIterable<? extends Node> nodes = graph.getNodes().filter(nodeCount.nodeClass());
+            Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count());
+        }
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Wed Feb 04 13:51:17 2015 +0100
@@ -67,7 +67,7 @@
         StructuredGraph graph = new StructuredGraph(javaMethod);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, conf, OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Wed Feb 04 13:51:17 2015 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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.compiler.test;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
+
+public class SchedulingTest extends GraphScheduleTest {
+
+    public static int testValueProxyInputsSnippet(int s) {
+        int i = 0;
+        while (true) {
+            i++;
+            int v = i - s * 2;
+            if (i == s) {
+                return v;
+            }
+        }
+    }
+
+    @Test
+    public void testValueProxyInputs() {
+        StructuredGraph graph = parseEager("testValueProxyInputsSnippet");
+        for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) {
+            fs.replaceAtUsages(null);
+            GraphUtil.killWithUnusedFloatingInputs(fs);
+        }
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST);
+        schedule.apply(graph);
+        NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock();
+        assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1);
+        LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first();
+        List<ValueNode> list = schedule.nodesFor(nodeToBlock.get(loopExit));
+        for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
+            if (!(node instanceof AddNode)) {
+                assertTrue(nodeToBlock.get(node) == nodeToBlock.get(loopExit));
+                assertTrue(list.indexOf(node) < list.indexOf(loopExit));
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Wed Feb 04 13:51:17 2015 +0100
@@ -152,7 +152,8 @@
         graph = new StructuredGraph(method);
         try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
             Assumptions assumptions = new Assumptions(false);
-            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
+                            OptimisticOptimizations.ALL).apply(graph);
             context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Wed Feb 04 13:51:17 2015 +0100
@@ -238,7 +238,7 @@
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
                     Assumptions assumptions = new Assumptions(false);
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, null, graphBuilderConfig, optimisticOpts);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     Debug.handle(ex);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Feb 04 13:51:17 2015 +0100
@@ -166,7 +166,7 @@
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
-        startGVNNumber = clazz.hashCode();
+        startGVNNumber = clazz.getName().hashCode();
 
         NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class);
         assert info != null : "Missing NodeInfo annotation on " + clazz;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Feb 04 13:51:17 2015 +0100
@@ -37,11 +37,13 @@
 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.*;
 
@@ -108,17 +110,24 @@
     public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
 
     @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
-    private static int getIndex(DynamicCounterNode counter) {
+    private static int getIndex(DynamicCounterNode counter, StructuredGraph currentGraph) {
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
         }
         String name;
         String group = counter.getGroup();
         if (counter.isWithContext()) {
-            StructuredGraph graph = counter.graph();
-            name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : graph.method().format("%h.%n"));
-            if (graph.name != null) {
-                name += " (" + graph.name + ")";
+            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;
 
@@ -374,20 +383,41 @@
         }
     }
 
+    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 class CounterIndexNode extends FloatingNode implements LIRLowerable {
+
+        protected final Object counter;
+        protected final int countersSize;
+
+        protected CounterIndexNode(Stamp stamp, DynamicCounterNode counter, int countersSize) {
+            super(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));
 
-        int index = BenchmarkCounters.getIndex(counter);
-        if (index >= config.graalCountersSize) {
-            throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
-        }
-        ConstantLocationNode arrayLocation = graph.unique(new ConstantLocationNode(COUNTER_LOCATION, config.graalCountersThreadOffset));
+        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));
-        ConstantLocationNode location = graph.unique(new ConstantLocationNode(COUNTER_LOCATION, Unsafe.ARRAY_LONG_INDEX_SCALE * index));
+        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));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Wed Feb 04 13:51:17 2015 +0100
@@ -41,12 +41,18 @@
 
     @Override
     public Object asObject(ResolvedJavaType type, JavaConstant constant) {
+        if (constant.isNull()) {
+            return null;
+        }
         HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant;
         return hsConstant.asObject(type);
     }
 
     @Override
     public <T> T asObject(Class<T> type, JavaConstant constant) {
+        if (constant.isNull()) {
+            return null;
+        }
         HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant;
         return hsConstant.asObject(type);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Wed Feb 04 13:51:17 2015 +0100
@@ -25,6 +25,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,17 +38,9 @@
 @ServiceProvider(GraphBuilderPluginsProvider.class)
 public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
     public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, ObjectPlugin.class);
-    }
-
-    /**
-     * HotSpot specific plugins for {@link Object}.
-     */
-    enum ObjectPlugin implements GraphBuilderPlugin {
-        getClass() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                assert args.length == 1;
-                ValueNode rcvr = args[0];
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("getClass", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
                 GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr));
                 StampProvider stampProvider = builder.getStampProvider();
                 LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi));
@@ -53,10 +48,6 @@
                 builder.push(Kind.Object, mirror);
                 return true;
             }
-        };
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name());
-        }
+        });
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Wed Feb 04 13:51:17 2015 +0100
@@ -36,6 +36,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -687,7 +688,10 @@
         Kind kind = field.getKind();
         T receiver = frameState.apop();
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+            GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ValueNode) receiver, (ResolvedJavaField) field)) {
+                appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+            }
         } else {
             handleUnresolvedLoadField(field, receiver);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java	Wed Feb 04 13:51:17 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Default implementation of {@link GraphBuilderPlugins} that uses a map.
+ */
+public class DefaultGraphBuilderPlugins implements GraphBuilderPlugins {
+
+    private final Map<ResolvedJavaMethod, InvocationPlugin> plugins = new HashMap<>();
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
+        assert InvocationPluginChecker.check(method, plugin);
+        GraphBuilderPlugin oldValue = plugins.put(method, plugin);
+        // System.out.println("registered: " + plugin);
+        assert oldValue == null;
+    }
+
+    /**
+     * Gets the plugin for a given method.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        return plugins.get(method);
+    }
+
+    @Override
+    public String toString() {
+        return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java	Wed Feb 04 11:31:26 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
- */
-@ServiceProvider(GraphBuilderPluginsProvider.class)
-public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
-    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, ObjectPlugin.class);
-        plugins.register(metaAccess, BoxingPlugin.class);
-    }
-
-    /**
-     * Plugins for {@link Object}.
-     */
-    enum ObjectPlugin implements GraphBuilderPlugin {
-        init() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode object = args[0];
-                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
-                    builder.append(new RegisterFinalizerNode(object));
-                }
-                return true;
-            }
-
-            public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-                return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, "<init>");
-            }
-        };
-
-        @Override
-        public String toString() {
-            return Object.class.getName() + "." + name() + "()";
-        }
-    }
-
-    /**
-     * Plugins for the standard primitive box classes (e.g., {@link Integer} and friends).
-     */
-    enum BoxingPlugin implements GraphBuilderPlugin {
-        valueOf$Boolean(Kind.Boolean),
-        booleanValue$Boolean(Kind.Boolean),
-        valueOf$Byte(Kind.Byte),
-        byteValue$Byte(Kind.Byte),
-        valueOf$Short(Kind.Short),
-        shortValue$Short(Kind.Short),
-        valueOf$Char(Kind.Char),
-        charValue$Char(Kind.Char),
-        valueOf$Int(Kind.Int),
-        intValue$Int(Kind.Int),
-        valueOf$Long(Kind.Long),
-        longValue$Long(Kind.Long),
-        valueOf$Float(Kind.Float),
-        floatValue$Float(Kind.Float),
-        valueOf$Double(Kind.Double),
-        doubleValue$Double(Kind.Double);
-
-        BoxingPlugin(Kind kind) {
-            assert name().startsWith("valueOf$") || name().startsWith(kind.getJavaName() + "Value$");
-            this.kind = kind;
-            this.box = name().charAt(0) == 'v';
-        }
-
-        private final Kind kind;
-        private final boolean box;
-
-        public final boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-            if (box) {
-                ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-                builder.push(Kind.Object, builder.append(new BoxNode(args[0], resultType, kind)));
-            } else {
-                builder.push(kind, builder.append(new UnboxNode(args[0], kind)));
-            }
-            return true;
-        }
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            Class<?>[] parameterTypes = box ? new Class<?>[]{kind.toJavaClass()} : new Class<?>[0];
-            return GraphBuilderPlugin.resolveTarget(metaAccess, kind.toBoxedJavaClass(), name(), parameterTypes);
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Feb 04 13:51:17 2015 +0100
@@ -37,6 +37,8 @@
     private final DebugInfoMode debugInfoMode;
     private final boolean doLivenessAnalysis;
     private final boolean inlineTrivial;
+    private GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin;
+    private GraphBuilderPlugins.ParameterPlugin parameterPlugin;
 
     public static enum DebugInfoMode {
         SafePointsOnly,
@@ -72,6 +74,12 @@
         this.inlineTrivial = inlineTrivial;
     }
 
+    public GraphBuilderConfiguration copy() {
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
+        result.loadFieldPlugin = loadFieldPlugin;
+        return result;
+    }
+
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
     }
@@ -93,6 +101,14 @@
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newInlineTrivial);
     }
 
+    public GraphBuilderPlugins.LoadFieldPlugin getLoadFieldPlugin() {
+        return loadFieldPlugin;
+    }
+
+    public void setLoadFieldPlugin(GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin) {
+        this.loadFieldPlugin = loadFieldPlugin;
+    }
+
     public ResolvedJavaType[] getSkippedExceptionTypes() {
         return skippedExceptionTypes;
     }
@@ -145,4 +161,12 @@
     public boolean shouldInlineTrivial() {
         return inlineTrivial;
     }
+
+    public GraphBuilderPlugins.ParameterPlugin getParameterPlugin() {
+        return parameterPlugin;
+    }
+
+    public void setParameterPlugin(GraphBuilderPlugins.ParameterPlugin parameterPlugin) {
+        this.parameterPlugin = parameterPlugin;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Feb 04 13:51:17 2015 +0100
@@ -42,6 +42,7 @@
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
@@ -63,12 +64,13 @@
 
     public GraphBuilderPhase(GraphBuilderConfiguration config) {
         this.graphBuilderConfig = config;
-        this.graphBuilderPlugins = new GraphBuilderPlugins();
+        this.graphBuilderPlugins = new DefaultGraphBuilderPlugins();
     }
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), graphBuilderConfig, graphBuilderPlugins, context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), context.getConstantReflection(), graphBuilderConfig, graphBuilderPlugins,
+                        context.getOptimisticOptimizations()).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
@@ -92,6 +94,7 @@
         private final OptimisticOptimizations optimisticOpts;
         private final StampProvider stampProvider;
         private final Assumptions assumptions;
+        private final ConstantReflectionProvider constantReflectionProvider;
 
         /**
          * Gets the graph being processed by this builder.
@@ -100,19 +103,21 @@
             return currentGraph;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins,
-                        OptimisticOptimizations optimisticOpts) {
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
             this.assumptions = assumptions;
             this.graphBuilderPlugins = graphBuilderPlugins;
+            this.constantReflectionProvider = constantReflectionProvider;
             assert metaAccess != null;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
-            this(metaAccess, stampProvider, assumptions, graphBuilderConfig, null, optimisticOpts);
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+            this(metaAccess, stampProvider, assumptions, constantReflectionProvider, graphBuilderConfig, null, optimisticOpts);
         }
 
         @Override
@@ -123,7 +128,7 @@
             assert method.getCode() != null : "method must contain bytecodes: " + method;
             this.currentGraph = graph;
             HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, null);
-            frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving());
+            frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving(), this.graphBuilderConfig.getParameterPlugin());
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
                 BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI);
@@ -557,7 +562,7 @@
 
             @Override
             protected ValueNode genObjectEquals(ValueNode x, ValueNode y) {
-                return new ObjectEqualsNode(x, y);
+                return ObjectEqualsNode.create(x, y, constantReflectionProvider);
             }
 
             @Override
@@ -773,11 +778,10 @@
                 if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect()) {
 
                     if (graphBuilderPlugins != null) {
-                        GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod);
+                        InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod);
                         if (plugin != null) {
                             int beforeStackSize = frameState.stackSize;
-                            if (plugin.handleInvocation(this, args)) {
-                                // System.out.println("used plugin: " + plugin);
+                            if (plugin.apply(this, args)) {
                                 assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize;
                                 return;
                             }
@@ -998,7 +1002,6 @@
             }
 
             public <T extends FloatingNode> T append(T v) {
-                assert !(v instanceof ConstantNode);
                 T added = currentGraph.unique(v);
                 return added;
             }
@@ -1482,11 +1485,24 @@
                 }
                 condition = genUnique(condition);
 
-                ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
-                ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
+                if (condition instanceof LogicConstantNode) {
+                    LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
+                    boolean value = constantLogicNode.getValue();
+                    if (negate) {
+                        value = !value;
+                    }
+                    BciBlock nextBlock = falseBlock;
+                    if (value) {
+                        nextBlock = trueBlock;
+                    }
+                    appendGoto(createTarget(nextBlock, frameState));
+                } else {
+                    ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
+                    ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
-                ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability);
-                append(ifNode);
+                    ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability);
+                    append(ifNode);
+                }
             }
 
             public StampProvider getStampProvider() {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Wed Feb 04 13:51:17 2015 +0100
@@ -22,43 +22,14 @@
  */
 package com.oracle.graal.java;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-
 /**
- * Extensions for handling certain bytecode instructions while building a
- * {@linkplain StructuredGraph graph} from a bytecode stream.
+ * Marker interface for graph builder plugins.
+ *
+ * Concrete plugins implement one of the sub-interfaces of this interface.
+ *
+ * @see GraphBuilderPluginsProvider
+ * @see GraphBuilderPlugins
+ * @see GraphBuilderPlugins.Registration
  */
 public interface GraphBuilderPlugin {
-
-    /**
-     * Processes an invocation parsed in a bytecode stream and add nodes to a graph being
-     * constructed that implement the semantics of the invocation.
-     *
-     * @param builder object being used to build a graph
-     * @param args the arguments to the invocation
-     */
-    boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args);
-
-    /**
-     * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} .
-     */
-    ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess);
-
-    /**
-     * Looks up a {@link ResolvedJavaMethod}.
-     *
-     * @param methodNameBase the name of the method is the prefix of this value up to the first '$'
-     *            character
-     */
-    static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class<?> declaringClass, String methodNameBase, Class<?>... parameterTypes) {
-        int index = methodNameBase.indexOf('$');
-        String methodName = index == -1 ? methodNameBase : methodNameBase.substring(0, index);
-        try {
-            return metaAccess.lookupJavaMethod(methodName.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes));
-        } catch (NoSuchMethodException | SecurityException e) {
-            throw new GraalInternalError(e);
-        }
-    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Wed Feb 04 13:51:17 2015 +0100
@@ -22,45 +22,225 @@
  */
 package com.oracle.graal.java;
 
+import static java.lang.String.*;
+
+import java.lang.reflect.*;
 import java.util.*;
-import java.util.stream.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 
 /**
- * A repository of {@link GraphBuilderPlugin}s.
+ * Interface for managing a set of graph builder {@link GraphBuilderPlugin}s.
  */
-public class GraphBuilderPlugins {
+public interface GraphBuilderPlugins {
 
-    private final Map<ResolvedJavaMethod, GraphBuilderPlugin> map = new HashMap<>();
+    public interface LoadFieldPlugin extends GraphBuilderPlugin {
+        boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field);
+    }
+
+    public interface ParameterPlugin extends GraphBuilderPlugin {
+        FloatingNode interceptParameter(int index);
+    }
 
     /**
-     * Registers all the constants of an enum that implements {@link GraphBuilderPlugin}.
+     * Plugin for handling a method invocation.
      */
-    public <T extends Enum<T> & GraphBuilderPlugin> void register(MetaAccessProvider metaAccess, Class<T> enumClass) {
-        assert Enum.class.isAssignableFrom(enumClass);
-        Object[] enumConstants = enumClass.getEnumConstants();
-        for (Object o : enumConstants) {
-            GraphBuilderPlugin gbp = (GraphBuilderPlugin) o;
-            ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess);
-            GraphBuilderPlugin oldValue = map.put(target, gbp);
-            // System.out.println("registered: " + gbp);
-            assert oldValue == null;
+    public interface InvocationPlugin extends GraphBuilderPlugin {
+        /**
+         * Tries to handle an invocation to a method with no arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder) {
+            throw invalidHandler(builder);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with one argument.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg) {
+            throw invalidHandler(builder, arg);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with two arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
+            throw invalidHandler(builder, arg1, arg2);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with three arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+            throw invalidHandler(builder, arg1, arg2, arg3);
+        }
+
+        default boolean apply(GraphBuilderContext builder, ValueNode[] args) {
+            if (args.length == 0) {
+                return apply(builder);
+            } else if (args.length == 1) {
+                return apply(builder, args[0]);
+            } else if (args.length == 2) {
+                return apply(builder, args[0], args[1]);
+            } else if (args.length == 3) {
+                return apply(builder, args[0], args[1], args[2]);
+            } else {
+                throw invalidHandler(builder, args);
+            }
+        }
+
+        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) {
+            return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length);
         }
     }
 
     /**
-     * Gets the plugin for a given method registered in the object.
+     * Utility for {@linkplain GraphBuilderPlugins#register(ResolvedJavaMethod, InvocationPlugin)
+     * registration} of plugins.
+     */
+    public static class Registration {
+
+        /**
+         * Sentinel class for use with {@link Registration#register1},
+         * {@link Registration#register2} or {@link Registration#register3} to denote the receiver
+         * argument for a non-static method.
+         */
+        public static final class Receiver {
+            private Receiver() {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        private final GraphBuilderPlugins plugins;
+        private final MetaAccessProvider metaAccess;
+        private final Class<?> declaringClass;
+
+        /**
+         * Creates an object for registering plugins for methods declared by a given class.
+         *
+         * @param plugins where to register the plugins
+         * @param metaAccess used to resolve classes and methods
+         * @param declaringClass the class declaring the methods for which plugins will be
+         *            registered via this object
+         */
+        public Registration(GraphBuilderPlugins plugins, MetaAccessProvider metaAccess, Class<?> declaringClass) {
+            this.plugins = plugins;
+            this.metaAccess = metaAccess;
+            this.declaringClass = declaringClass;
+        }
+
+        /**
+         * Registers a plugin for a method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register0(String name, InvocationPlugin plugin) {
+            plugins.register(resolve(metaAccess, declaringClass, name), plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Resolves a method given a declaring class, name and parameter types.
+         */
+        public static ResolvedJavaMethod resolve(MetaAccessProvider metaAccess, Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+            try {
+                return metaAccess.lookupJavaMethod(name.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(name, parameterTypes));
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+    }
+
+    public static class InvocationPluginChecker {
+        static final Class<?>[] APPLY0 = {GraphBuilderContext.class};
+        static final Class<?>[] APPLY1 = {GraphBuilderContext.class, ValueNode.class};
+        static final Class<?>[] APPLY2 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class};
+        static final Class<?>[] APPLY3 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class, ValueNode.class};
+        static final Class<?>[][] SIGS = {APPLY0, APPLY1, APPLY2, APPLY3};
+
+        public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) {
+            int arguments = method.getSignature().getParameterCount(!method.isStatic());
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)"));
+            Method expected = null;
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    assert Arrays.equals(SIGS[arguments], parameterTypes) : format("graph builder plugin for %s has wrong signature%nexpected: (%s)%n  actual: (%s)", method.format("%H.%n(%p)"),
+                                    sigString(SIGS[arguments]), sigString(m.getParameterTypes()));
+                    expected = m;
+                }
+            }
+            assert expected != null : format("graph builder plugin %s must define exactly one \"apply\" method, none found", plugin);
+            return true;
+        }
+
+        protected static String sigString(Class<?>... sig) {
+            StringBuilder sb = new StringBuilder();
+            for (Class<?> t : sig) {
+                if (sb.length() != 0) {
+                    sb.append(", ");
+                }
+                sb.append(t.getSimpleName());
+            }
+            return sb.toString();
+        }
+
+    }
+
+    /**
+     * Registers an {@link InvocationPlugin} for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    void register(ResolvedJavaMethod method, InvocationPlugin plugin);
+
+    /**
+     * Gets the {@link InvocationPlugin} for a given method.
      *
      * @param method the method to lookup
      * @return the plugin associated with {@code method} or {@code null} if none exists
      */
-    public GraphBuilderPlugin getPlugin(ResolvedJavaMethod method) {
-        return map.get(method);
-    }
-
-    @Override
-    public String toString() {
-        return map.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
-    }
+    InvocationPlugin lookupInvocation(ResolvedJavaMethod method);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Wed Feb 04 13:51:17 2015 +0100
@@ -30,9 +30,7 @@
  */
 public interface GraphBuilderPluginsProvider extends Service {
     /**
-     * Registers the plugins provided by this object with a plugins registry.
-     *
-     * @param plugins registry of plugins
+     * Registers the plugins provided by this object.
      */
     void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Wed Feb 04 13:51:17 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.java.GraphBuilderPlugins.ParameterPlugin;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -81,14 +82,20 @@
         }
     }
 
-    public final void initializeForMethodStart(boolean eagerResolve) {
+    public final void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
 
         int javaIndex = 0;
         int index = 0;
         if (!method.isStatic()) {
             // add the receiver
-            ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())));
-            storeLocal(javaIndex, receiver);
+            FloatingNode receiver = null;
+            if (parameterPlugin != null) {
+                receiver = parameterPlugin.interceptParameter(index);
+            }
+            if (receiver == null) {
+                receiver = new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()));
+            }
+            storeLocal(javaIndex, graph.unique(receiver));
             javaIndex = 1;
             index = 1;
         }
@@ -107,8 +114,14 @@
             } else {
                 stamp = StampFactory.forKind(kind);
             }
-            ParameterNode param = graph.unique(new ParameterNode(index, stamp));
-            storeLocal(javaIndex, param);
+            FloatingNode param = null;
+            if (parameterPlugin != null) {
+                param = parameterPlugin.interceptParameter(index);
+            }
+            if (param == null) {
+                param = new ParameterNode(index, stamp);
+            }
+            storeLocal(javaIndex, graph.unique(param));
             javaIndex += kind.getSlotCount();
             index++;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Wed Feb 04 13:51:17 2015 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
+ */
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class StandardGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("<init>", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode object) {
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
+                }
+                return true;
+            }
+        });
+
+        for (Kind kind : Kind.values()) {
+            if (kind.isPrimitive() && kind != Kind.Void) {
+                new BoxPlugin(kind).register(metaAccess, plugins);
+                new UnboxPlugin(kind).register(metaAccess, plugins);
+            }
+        }
+    }
+
+    static class BoxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        BoxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnboxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        UnboxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            builder.push(kind, builder.append(new UnboxNode(value, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
+            plugins.register(method, this);
+        }
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Feb 04 13:51:17 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.debug.*;
 
 public abstract class LoopPolicies {
 
@@ -45,7 +46,17 @@
         }
         LoopBeginNode loopBegin = loop.loopBegin();
         double entryProbability = probabilities.applyAsDouble(loopBegin.forwardEnd());
-        return entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue();
+        if (entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue()) {
+            // check whether we're allowed to peel this loop
+            for (Node node : loop.inside().nodes()) {
+                if (node instanceof ControlFlowAnchorNode) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
     }
 
     public static boolean shouldFullUnroll(LoopEx loop) {
@@ -57,7 +68,17 @@
         int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue() : FullUnrollMaxNodes.getValue();
         maxNodes = Math.min(maxNodes, MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount());
         int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
-        return size * maxTrips <= maxNodes;
+        if (size * maxTrips <= maxNodes) {
+            // check whether we're allowed to unroll this loop
+            for (Node node : loop.inside().nodes()) {
+                if (node instanceof ControlFlowAnchorNode) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
     }
 
     public static boolean shouldTryUnswitch(LoopEx loop) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -69,18 +69,21 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        /*
-         * Don't allow guards with action None and reason RuntimeConstraint to float. In cases where
-         * 2 guards are testing equivalent conditions they might be lowered at the same location. If
-         * the guard with the None action is lowered before the the other guard then the code will
-         * be stuck repeatedly deoptimizing without invalidating the code. Conditional elimination
-         * will eliminate the guard if it's truly redundant in this case.
-         */
-        if (graph().getGuardsStage().allowsFloatingGuards() && (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint)) {
-            ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode();
-            this.replaceAtUsages(guard);
-            ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
-            graph().replaceFixedWithFixed(this, newAnchor);
+        if (graph().getGuardsStage().allowsFloatingGuards()) {
+            /*
+             * Don't allow guards with action None and reason RuntimeConstraint to float. In cases
+             * where 2 guards are testing equivalent conditions they might be lowered at the same
+             * location. If the guard with the None action is lowered before the the other guard
+             * then the code will be stuck repeatedly deoptimizing without invalidating the code.
+             * Conditional elimination will eliminate the guard if it's truly redundant in this
+             * case.
+             */
+            if (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint) {
+                ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode();
+                this.replaceAtUsages(guard);
+                ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
+                graph().replaceFixedWithFixed(this, newAnchor);
+            }
         } else {
             lowerToIf().lower(tool);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -78,9 +78,19 @@
     }
 
     /**
-     * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, ordered
-     * in increasing {@link #phiPredecessorIndex}. This method is suited to create new loop
-     * {@link PhiNode}.
+     * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, in
+     * increasing {@link #phiPredecessorIndex} order. This method is suited to create new loop
+     * {@link PhiNode}.<br>
+     *
+     * For example a new PhiNode may be added as follow:
+     *
+     * <pre>
+     * PhiNode phi = new ValuePhiNode(stamp, loop);
+     * phi.addInput(forwardEdgeValue);
+     * for (LoopEndNode loopEnd : loop.orderedLoopEnds()) {
+     *     phi.addInput(backEdgeValue(loopEnd));
+     * }
+     * </pre>
      *
      * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
      */
@@ -165,7 +175,7 @@
         return super.verify();
     }
 
-    public int nextEndIndex() {
+    int nextEndIndex() {
         return nextEndIndex++;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -28,6 +28,10 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
 
+/**
+ * LoopEnd nodes represent a loop back-edge. When a LoopEnd is reached, execution continues at the
+ * {@linkplain #loopBegin() loop header}.
+ */
 @NodeInfo
 public class LoopEndNode extends AbstractEndNode {
 
@@ -79,17 +83,18 @@
     }
 
     /**
-     * Returns the 0-based index of this loop end. This is <b>not</b> the index into {@link PhiNode}
-     * values at the loop begin. Use {@link AbstractMergeNode#phiPredecessorIndex(AbstractEndNode)}
-     * for this purpose.
+     * Returns the index of this loop end amongst its {@link LoopBeginNode}'s loop ends.<br>
      *
-     * @return The 0-based index of this loop end.
+     * Since a LoopBeginNode also has {@linkplain LoopBeginNode#forwardEnds() forward ends}, this is
+     * <b>not</b> the index into {@link PhiNode} values at the loop begin. Use
+     * {@link LoopBeginNode#phiPredecessorIndex(AbstractEndNode)} for this purpose.
+     *
      */
-    public int endIndex() {
+    int endIndex() {
         return endIndex;
     }
 
-    public void setEndIndex(int idx) {
+    void setEndIndex(int idx) {
         this.endIndex = idx;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -39,14 +39,19 @@
 @NodeInfo
 public abstract class CompareNode extends BinaryOpLogicNode {
 
+    protected final Condition condition;
+    protected final boolean unorderedIsTrue;
+
     /**
      * Constructs a new Compare instruction.
      *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
-    public CompareNode(ValueNode x, ValueNode y) {
+    public CompareNode(Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
         super(x, y);
+        this.condition = condition;
+        this.unorderedIsTrue = unorderedIsTrue;
     }
 
     /**
@@ -54,14 +59,18 @@
      *
      * @return the condition
      */
-    public abstract Condition condition();
+    public final Condition condition() {
+        return condition;
+    }
 
     /**
      * Checks whether unordered inputs mean true or false (only applies to float operations).
      *
      * @return {@code true} if unordered inputs produce true
      */
-    public abstract boolean unorderedIsTrue();
+    public final boolean unorderedIsTrue() {
+        return this.unorderedIsTrue;
+    }
 
     private ValueNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
         Constant trueConstant = conditionalNode.trueValue().asConstant();
@@ -93,8 +102,10 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && forY.isConstant()) {
-            return LogicConstantNode.forBoolean(condition().foldCondition(forX.asConstant(), forY.asConstant(), tool.getConstantReflection(), unorderedIsTrue()));
+        ConstantReflectionProvider constantReflection = tool.getConstantReflection();
+        LogicNode constantCondition = tryConstantFold(condition(), forX, forY, constantReflection, unorderedIsTrue());
+        if (constantCondition != null) {
+            return constantCondition;
         }
         ValueNode result;
         if (forX.isConstant()) {
@@ -115,7 +126,14 @@
         return this;
     }
 
-    protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY);
+    public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
+        if (forX.isConstant() && forY.isConstant() && constantReflection != null) {
+            return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue));
+        }
+        return null;
+    }
+
+    protected abstract LogicNode duplicateModified(ValueNode newX, ValueNode newY);
 
     protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
         if (nonConstant instanceof ConditionalNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -31,22 +32,21 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
-public class FloatEqualsNode extends CompareNode {
+public final class FloatEqualsNode extends CompareNode {
 
     public FloatEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.EQ, false, x, y);
         assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp : x.stamp() + " " + y.stamp();
         assert x.stamp().isCompatible(y.stamp());
     }
 
-    @Override
-    public Condition condition() {
-        return Condition.EQ;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            return new FloatEqualsNode(x, y);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -33,23 +33,10 @@
 @NodeInfo(shortName = "<")
 public class FloatLessThanNode extends CompareNode {
 
-    protected final boolean unorderedIsTrue;
-
     public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
-        super(x, y);
+        super(Condition.LT, unorderedIsTrue, x, y);
         assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp;
         assert x.stamp().isCompatible(y.stamp());
-        this.unorderedIsTrue = unorderedIsTrue;
-    }
-
-    @Override
-    public Condition condition() {
-        return Condition.LT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return unorderedIsTrue;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -33,22 +33,12 @@
 public class IntegerBelowNode extends CompareNode {
 
     public IntegerBelowNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.BT, false, x, y);
         assert x.stamp() instanceof IntegerStamp;
         assert y.stamp() instanceof IntegerStamp;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.BT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         ValueNode result = super.canonical(tool, forX, forY);
         if (result != this) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -35,22 +35,12 @@
 public class IntegerEqualsNode extends CompareNode {
 
     public IntegerEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.EQ, false, x, y);
         assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
         assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.EQ;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         PrimitiveConstant primitive = (PrimitiveConstant) constant;
         if (primitive.getKind() == Kind.Int && primitive.asInt() == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -35,22 +35,12 @@
 public class IntegerLessThanNode extends CompareNode {
 
     public IntegerLessThanNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.LT, false, x, y);
         assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
         assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.LT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         PrimitiveConstant primitive = (PrimitiveConstant) constant;
         assert condition() == Condition.LT;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -44,7 +44,7 @@
         if (forX.isConstant() && forY.isConstant()) {
             return LogicConstantNode.forBoolean((forX.asJavaConstant().asLong() & forY.asJavaConstant().asLong()) == 0);
         }
-        if (getX().stamp() instanceof IntegerStamp && getY().stamp() instanceof IntegerStamp) {
+        if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
             IntegerStamp xStamp = (IntegerStamp) forX.stamp();
             IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if ((xStamp.upMask() & yStamp.upMask()) == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -55,7 +55,7 @@
         LogicNode equalComp;
         LogicNode lessComp;
         if (getX().stamp() instanceof FloatStamp) {
-            equalComp = graph().unique(new FloatEqualsNode(getX(), getY()));
+            equalComp = graph().unique(FloatEqualsNode.create(getX(), getY(), tool.getConstantReflection()));
             lessComp = graph().unique(new FloatLessThanNode(getX(), getY(), isUnorderedLess));
         } else {
             equalComp = graph().unique(new IntegerEqualsNode(getX(), getY()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -38,6 +39,15 @@
         assert y.stamp() instanceof AbstractObjectStamp;
     }
 
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            return new ObjectEqualsNode(x, y);
+        }
+    }
+
     private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
         if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) {
             if (other.isConstant()) {
@@ -75,7 +85,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 * 
+                 *
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -33,22 +33,12 @@
 public class PointerEqualsNode extends CompareNode {
 
     public PointerEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(Condition.EQ, false, x, y);
         assert x.stamp() instanceof AbstractPointerStamp;
         assert y.stamp() instanceof AbstractPointerStamp;
     }
 
     @Override
-    public Condition condition() {
-        return Condition.EQ;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
             return LogicConstantNode.tautology();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Wed Feb 04 13:51:17 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.debug;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -47,4 +48,9 @@
     public void generate(NodeLIRBuilderTool generator) {
         // do nothing
     }
+
+    @Override
+    protected void afterClone(Node other) {
+        assert false : this + " should never be cloned";
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Feb 04 13:51:17 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -192,7 +193,7 @@
         int fixedCount = 0;
         while (fixed instanceof FixedWithNextNode) {
             fixed = ((FixedWithNextNode) fixed).next();
-            if (fixed instanceof CommitAllocationNode) {
+            if (fixed instanceof CommitAllocationNode || fixed instanceof ControlFlowAnchorNode) {
                 return false;
             }
             fixedCount++;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Feb 04 13:51:17 2015 +0100
@@ -619,8 +619,8 @@
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(
-                                    graph);
+                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, replacements.providers.getConstantReflection(),
+                                    GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
                 }
                 afterParsing(graph);
 
@@ -633,9 +633,9 @@
             return graph;
         }
 
-        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts) {
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
+        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, constantReflectionProvider, graphBuilderConfig, optimisticOpts);
         }
 
         protected void afterParsing(StructuredGraph graph) {
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Feb 04 13:51:17 2015 +0100
@@ -177,7 +177,8 @@
         Suites suites = suitesProvider.createSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
+                        OptimisticOptimizations.ALL).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java	Wed Feb 04 13:51:17 2015 +0100
@@ -38,14 +38,14 @@
     public DefaultTruffleSplittingStrategyNew(OptimizedDirectCallNode call) {
         this.call = call;
         this.splitStart = TruffleCompilerOptions.TruffleSplittingStartCallCount.getValue();
-        this.splittingEnabled = isSplittingEnabled();
+        this.splittingEnabled = isSplittingEnabled(call);
         this.argumentStamp = DefaultTruffleStamp.getInstance();
         if (TruffleCompilerOptions.TruffleSplittingAggressive.getValue()) {
             splittingForced = true;
         }
     }
 
-    private boolean isSplittingEnabled() {
+    private static boolean isSplittingEnabled(OptimizedDirectCallNode call) {
         if (!TruffleCompilerOptions.TruffleSplitting.getValue()) {
             return false;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Feb 04 13:51:17 2015 +0100
@@ -36,9 +36,11 @@
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
+import com.oracle.graal.java.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -70,15 +72,26 @@
     private final TruffleCache truffleCache;
     private final SnippetReflectionProvider snippetReflection;
     private final ResolvedJavaMethod callDirectMethod;
+    private final ResolvedJavaMethod callInlinedMethod;
     private final ResolvedJavaMethod callSiteProxyMethod;
+    protected final ResolvedJavaMethod callRootMethod;
+    private final GraphBuilderConfiguration configForRoot;
 
-    public PartialEvaluator(Providers providers, TruffleCache truffleCache, SnippetReflectionProvider snippetReflection) {
+    public PartialEvaluator(Providers providers, GraphBuilderConfiguration configForRoot, TruffleCache truffleCache, SnippetReflectionProvider snippetReflection) {
         this.providers = providers;
         this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
         this.snippetReflection = snippetReflection;
         this.truffleCache = truffleCache;
         this.callDirectMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod());
+        this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod());
         this.callSiteProxyMethod = providers.getMetaAccess().lookupJavaMethod(GraalFrameInstance.CallNodeFrame.METHOD);
+        this.configForRoot = configForRoot;
+
+        try {
+            callRootMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class));
+        } catch (NoSuchMethodException ex) {
+            throw new RuntimeException(ex);
+        }
     }
 
     public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) {
@@ -91,65 +104,34 @@
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
-        final StructuredGraph graph = truffleCache.createRootGraph(callTarget.toString());
+
+        final StructuredGraph graph = new StructuredGraph(callTarget.toString(), callRootMethod);
         assert graph != null : "no graph for root method";
 
         try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph)) {
-            // Canonicalize / constant propagate.
-            PhaseContext baseContext = new PhaseContext(providers, assumptions);
-
-            injectConstantCallTarget(graph, callTarget, baseContext);
-
-            Debug.dump(graph, "Before expansion");
-
-            TruffleExpansionLogger expansionLogger = null;
-            if (TraceTruffleExpansion.getValue()) {
-                expansionLogger = new TruffleExpansionLogger(providers, graph);
-            }
 
-            expandTree(graph, assumptions, expansionLogger);
+            Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
+            if (CacheGraphs.getValue()) {
+                graphCache = new HashMap<>();
+            }
+            PhaseContext baseContext = new PhaseContext(providers, assumptions);
+            HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
 
-            TruffleInliningCache inliningCache = null;
-            if (TruffleFunctionInlining.getValue()) {
-                callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-                if (TruffleFunctionInliningCache.getValue()) {
-                    inliningCache = new TruffleInliningCache();
-                }
+            if (TruffleCompilerOptions.FastPE.getValue()) {
+                fastPartialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
+            } else {
+                createRootGraph(graph);
+                partialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
             }
 
-            expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache);
-
             if (Thread.currentThread().isInterrupted()) {
                 return null;
             }
 
             new VerifyFrameDoesNotEscapePhase().apply(graph, false);
-
             if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) {
                 createHistogram();
             }
-
-            canonicalizer.apply(graph, baseContext);
-            Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
-            if (CacheGraphs.getValue()) {
-                graphCache = new HashMap<>();
-            }
-            HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
-
-            // EA frame and clean up.
-            do {
-                try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
-                    new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
-                    new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext);
-                } catch (Throwable t) {
-                    Debug.handle(t);
-                }
-            } while (expandTree(graph, assumptions, expansionLogger));
-
-            if (expansionLogger != null) {
-                expansionLogger.print(callTarget);
-            }
-
             postPartialEvaluation(graph);
 
         } catch (Throwable e) {
@@ -159,6 +141,104 @@
         return graph;
     }
 
+    private class InterceptLoadFieldPlugin implements GraphBuilderPlugins.LoadFieldPlugin {
+
+        public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+            System.out.println("Load field plugin called for receiver: " + receiver + " and field " + field);
+
+            if (receiver.isConstant()) {
+                JavaConstant asJavaConstant = receiver.asJavaConstant();
+                JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant);
+                if (result != null) {
+                    ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess()));
+                    builder.push(constantNode.getKind(), constantNode);
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private class InterceptReceiverPlugin implements GraphBuilderPlugins.ParameterPlugin {
+
+        private final Object receiver;
+
+        public InterceptReceiverPlugin(Object receiver) {
+            this.receiver = receiver;
+        }
+
+        public FloatingNode interceptParameter(int index) {
+            if (index == 0) {
+                return ConstantNode.forConstant(snippetReflection.forObject(receiver), providers.getMetaAccess());
+            }
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void fastPartialEvaluation(OptimizedCallTarget callTarget, Assumptions assumptions, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
+        GraphBuilderConfiguration newConfig = configForRoot.copy();
+        newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
+        newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations).apply(graph);
+        Debug.dump(graph, "After FastPE");
+    }
+
+    private void partialEvaluation(final OptimizedCallTarget callTarget, final Assumptions assumptions, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
+        injectConstantCallTarget(graph, callTarget, baseContext);
+
+        Debug.dump(graph, "Before expansion");
+
+        TruffleExpansionLogger expansionLogger = null;
+        if (TraceTruffleExpansion.getValue()) {
+            expansionLogger = new TruffleExpansionLogger(providers, graph);
+        }
+
+        expandTree(graph, assumptions, expansionLogger);
+
+        TruffleInliningCache inliningCache = null;
+        if (TruffleFunctionInlining.getValue()) {
+            callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
+            if (TruffleFunctionInliningCache.getValue()) {
+                inliningCache = new TruffleInliningCache();
+            }
+        }
+
+        expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache);
+
+        if (Thread.currentThread().isInterrupted()) {
+            return;
+        }
+
+        canonicalizer.apply(graph, baseContext);
+        // EA frame and clean up.
+        do {
+            try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
+                new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
+                new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext);
+            } catch (Throwable t) {
+                Debug.handle(t);
+            }
+        } while (expandTree(graph, assumptions, expansionLogger));
+
+        if (expansionLogger != null) {
+            expansionLogger.print(callTarget);
+        }
+    }
+
+    public StructuredGraph createRootGraph(StructuredGraph graph) {
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot,
+                        TruffleCompilerImpl.Optimizations).apply(graph);
+        return graph;
+    }
+
+    public StructuredGraph createInlineGraph(String name) {
+        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot,
+                        TruffleCompilerImpl.Optimizations).apply(graph);
+        return graph;
+    }
+
     private static void postPartialEvaluation(final StructuredGraph graph) {
         NeverPartOfCompilationNode.verifyNotFoundIn(graph);
         for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
@@ -464,7 +544,7 @@
     private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, TruffleInliningDecision decision) {
         try (Scope s = Debug.scope("GuestLanguageInlinedGraph", new DebugDumpScope(decision.getTarget().toString()))) {
             OptimizedCallTarget target = decision.getTarget();
-            StructuredGraph inlineGraph = truffleCache.createInlineGraph(target.toString());
+            StructuredGraph inlineGraph = createInlineGraph(target.toString());
             injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext);
             TruffleExpansionLogger expansionLogger = null;
             if (TraceTruffleExpansion.getValue()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Wed Feb 04 13:51:17 2015 +0100
@@ -30,13 +30,6 @@
 public interface TruffleCache {
 
     /**
-     * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#callBoundary}.
-     */
-    StructuredGraph createRootGraph(String name);
-
-    StructuredGraph createInlineGraph(String name);
-
-    /**
      * Returns a cached graph for a method with given arguments.
      */
     StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final CanonicalizerPhase finalCanonicalizer);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Feb 04 13:51:17 2015 +0100
@@ -56,7 +56,6 @@
 
     private final Providers providers;
     private final GraphBuilderConfiguration config;
-    private final GraphBuilderConfiguration configForRoot;
     private final OptimisticOptimizations optimisticOptimizations;
 
     private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
@@ -68,40 +67,17 @@
     private final ResolvedJavaType errorClass;
     private final ResolvedJavaType controlFlowExceptionClass;
 
-    protected final ResolvedJavaMethod callRootMethod;
-    protected final ResolvedJavaMethod callInlinedMethod;
-
     private long counter;
 
-    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRoot, OptimisticOptimizations optimisticOptimizations) {
+    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) {
         this.providers = providers;
         this.config = config;
-        this.configForRoot = configForRoot;
         this.optimisticOptimizations = optimisticOptimizations;
 
         this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class);
         this.runtimeExceptionClass = providers.getMetaAccess().lookupJavaType(RuntimeException.class);
         this.errorClass = providers.getMetaAccess().lookupJavaType(Error.class);
         this.controlFlowExceptionClass = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
-
-        try {
-            callRootMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class));
-        } catch (NoSuchMethodException ex) {
-            throw new RuntimeException(ex);
-        }
-        this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod());
-    }
-
-    public StructuredGraph createInlineGraph(String name) {
-        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), config, TruffleCompilerImpl.Optimizations).apply(graph);
-        return graph;
-    }
-
-    public StructuredGraph createRootGraph(String name) {
-        StructuredGraph graph = new StructuredGraph(name, callRootMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
-        return graph;
     }
 
     private static List<Object> computeCacheKey(ResolvedJavaMethod method, NodeInputList<ValueNode> arguments) {
@@ -294,7 +270,7 @@
 
     protected StructuredGraph parseGraph(final ResolvedJavaMethod method, final PhaseContext phaseContext) {
         final StructuredGraph graph = new StructuredGraph(method);
-        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), config, optimisticOptimizations).apply(graph);
+        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), null, config, optimisticOptimizations).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Feb 04 13:51:17 2015 +0100
@@ -84,9 +84,9 @@
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
         this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
-        this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations);
+        this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, TruffleCompilerImpl.Optimizations);
 
-        this.partialEvaluator = new PartialEvaluator(providers, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class));
+        this.partialEvaluator = new PartialEvaluator(providers, config, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class));
 
         if (Debug.isEnabled()) {
             DebugEnvironment.initialize(System.out);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Wed Feb 04 11:31:26 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Wed Feb 04 13:51:17 2015 +0100
@@ -28,6 +28,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.truffle.nodes.frame.*;
@@ -39,96 +41,69 @@
 @ServiceProvider(GraphBuilderPluginsProvider.class)
 public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
     public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, CompilerDirectivesPlugin.class);
-    }
-
-    /**
-     * Plugins for {@link CompilerDirectives}.
-     */
-    enum CompilerDirectivesPlugin implements GraphBuilderPlugin {
-        inInterpreter() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(ConstantNode.forBoolean(false));
+        Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class);
+        r.register0("inInterpreter", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(false)));
                 return true;
             }
-        },
-        inCompiledCode() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(ConstantNode.forBoolean(true));
+        });
+        r.register0("inCompiledCode", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
                 return true;
             }
-        },
-        transferToInterpreter() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register0("transferToInterpreter", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
                 builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
-        },
-        transferToInterpreterAndInvalidate() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
                 builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
-        },
-        interpreterOnly(Runnable.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
                 return true;
             }
-        },
-        interpreterOnly$(Callable.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register1("interpreterOnly", Callable.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
                 return true;
             }
-        },
-        injectBranchProbability(double.class, boolean.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode probability = args[0];
-                ValueNode condition = args[1];
+        });
+        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
                 builder.append(new BranchProbabilityNode(probability, condition));
                 return true;
             }
-        },
-        bailout(String.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                // TODO: is this too eager? Should a BailoutNode be created instead?
-                ValueNode message = args[0];
+        });
+        r.register1("bailout", String.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode message) {
                 if (message.isConstant()) {
                     throw new BailoutException(message.asConstant().toValueString());
                 }
                 throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)");
             }
-        },
-
-        isCompilationConstant(Object.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode arg0 = args[0];
-                if (arg0 instanceof BoxNode) {
-                    arg0 = ((BoxNode) arg0).getValue();
-                }
-                if (arg0.isConstant()) {
+        });
+        r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
                     builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
                     return true;
                 }
-
-                // Cannot create MacroNodes in a plugin (yet)
                 return false;
             }
-        },
-        materialize(Object.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(new ForceMaterializeNode(args[0]));
+        });
+        r.register1("materialize", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.append(new ForceMaterializeNode(value));
                 return true;
             }
-        };
-
-        CompilerDirectivesPlugin(Class<?>... parameterTypes) {
-            this.parameterTypes = parameterTypes;
-        }
-
-        private final Class<?>[] parameterTypes;
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            return GraphBuilderPlugin.resolveTarget(metaAccess, CompilerDirectives.class, name(), parameterTypes);
-        }
+        });
     }
 }
--- a/mxtool/mx.py	Wed Feb 04 11:31:26 2015 +0100
+++ b/mxtool/mx.py	Wed Feb 04 13:51:17 2015 +0100
@@ -3440,7 +3440,10 @@
     print 'node [shape=rect];'
     for p in projects():
         for dep in p.canonical_deps():
-            print '"' + p.name + '"->"' + dep + '"'
+            print '"' + p.name + '"->"' + dep + '";'
+        if hasattr(p, '_declaredAnnotationProcessors'):
+            for ap in p._declaredAnnotationProcessors:
+                print '"' + p.name + '"->"' + ap + '" [style="dashed"];'
     print '}'
 
 def _source_locator_memento(deps):
--- a/test/blacklist_sparc.txt	Wed Feb 04 11:31:26 2015 +0100
+++ b/test/blacklist_sparc.txt	Wed Feb 04 13:51:17 2015 +0100
@@ -1,5 +1,4 @@
 com.oracle.graal.replacements.test.StandardMethodSubstitutionsTest
 com.oracle.graal.hotspot.amd64.test.CompressedNullCheckTest
-com.oracle.graal.compiler.test.ea.UnsafeEATest
-com.oracle.graal.truffle.test.SimplePartialEvaluationTest
-com.oracle.graal.replacements.test.ArraysSubstitutionsTest
+com.oracle.graal.hotspot.test.HotSpotCryptoSubstitutionTest
+