changeset 19101:212299803bf6

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Tue, 03 Feb 2015 17:03:19 +0100
parents d2ec5e56ed31 (current diff) 9865883b5114 (diff)
children 026749fff52c
files graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java
diffstat 40 files changed, 1313 insertions(+), 859 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	Tue Feb 03 17:03:19 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.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Tue Feb 03 17:03:19 2015 +0100
@@ -317,6 +317,49 @@
         return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(","));
     }
 
+    private boolean opsEquals(ArithmeticOpTable that) {
+        // @formatter:off
+        return Objects.equals(neg, that.neg) &&
+               Objects.equals(add, that.add) &&
+               Objects.equals(sub, that.sub) &&
+               Objects.equals(mul, that.mul) &&
+               Objects.equals(div, that.div) &&
+               Objects.equals(rem, that.rem) &&
+               Objects.equals(not, that.not) &&
+               Objects.equals(and, that.and) &&
+               Objects.equals(or, that.or) &&
+               Objects.equals(xor, that.xor) &&
+               Objects.equals(shl, that.shl) &&
+               Objects.equals(shr, that.shr) &&
+               Objects.equals(ushr, that.ushr) &&
+               Objects.equals(abs, that.abs) &&
+               Objects.equals(sqrt, that.sqrt) &&
+               Objects.equals(zeroExtend, that.zeroExtend) &&
+               Objects.equals(signExtend, that.signExtend) &&
+               Objects.equals(narrow, that.narrow);
+        // @formatter:on
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ArithmeticOpTable that = (ArithmeticOpTable) obj;
+        if (opsEquals(that)) {
+            if (Arrays.equals(this.floatConvert, that.floatConvert)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public String toString() {
         return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" +
@@ -337,19 +380,26 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
-            if (obj == this) {
-                return true;
-            }
-            if (obj != null && getClass() == obj.getClass()) {
-                return obj.toString().equals(toString());
-            }
-            return false;
+        public int hashCode() {
+            return operator.hashCode();
         }
 
         @Override
-        public int hashCode() {
-            return toString().hashCode();
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            Op that = (Op) obj;
+            if (operator.equals(that.operator)) {
+                return true;
+            }
+            return true;
         }
     }
 
@@ -533,6 +583,36 @@
         }
 
         @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + (associative ? 1231 : 1237);
+            result = prime * result + (commutative ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            BinaryOp<?> that = (BinaryOp<?>) obj;
+            if (associative != that.associative) {
+                return false;
+            }
+            if (commutative != that.commutative) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
         public String toString() {
             if (associative) {
                 if (commutative) {
@@ -611,6 +691,30 @@
         public FloatConvertOp unwrap() {
             return this;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            return prime * super.hashCode() + op.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            FloatConvertOp that = (FloatConvertOp) obj;
+            if (op != that.op) {
+                return false;
+            }
+            return true;
+        }
     }
 
     public abstract static class IntegerConvertOp<T> extends Op {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Tue Feb 03 17:03:19 2015 +0100
@@ -325,7 +325,7 @@
         canonicalizer.apply(graph, context);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         if (loopPeeling) {
-            new LoopTransformHighPhase().apply(graph);
+            new LoopPeelingPhase().apply(graph);
         }
         new DeadCodeEliminationPhase().apply(graph);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Feb 03 17:03:19 2015 +0100
@@ -124,7 +124,7 @@
         final StructuredGraph graph = parseEager(snippet);
         final StructuredGraph referenceGraph = parseEager(referenceSnippet);
 
-        new LoopTransformLowPhase().apply(graph);
+        new LoopUnswitchingPhase().apply(graph);
 
         // Framestates create comparison problems
         for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Tue Feb 03 17:03:19 2015 +0100
@@ -339,8 +339,7 @@
     @Test
     public void testPeeledLoop() {
         prepareGraph("testPeeledLoopSnippet", false);
-        new LoopTransformHighPhase().apply(graph);
-        new LoopTransformLowPhase().apply(graph);
+        new LoopPeelingPhase().apply(graph);
         new SchedulePhase().apply(graph);
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java	Tue Feb 03 17:03:19 2015 +0100
@@ -25,6 +25,8 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
 
 /**
  * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at
@@ -38,15 +40,31 @@
 public class GraalTutorial extends InvokeGraal {
 
     /*
+     * Example for the Graal API: access the Graal API metadata object for a method.
+     */
+
+    @Test
+    public void testPrintBytecodes() {
+        ResolvedJavaMethod method = findMethod(String.class, "hashCode");
+
+        byte[] bytecodes = method.getCode();
+        Assert.assertNotNull(bytecodes);
+
+        System.out.println(new BytecodeDisassembler().disassemble(method));
+    }
+
+    /*
      * A simple Graal compilation example: Compile the method String.hashCode()
      */
 
     @Test
     public void testStringHashCode() throws InvalidInstalledCodeException {
+        int expectedResult = "Hello World".hashCode();
+
         InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode"));
 
         int result = (int) installedCode.executeVarargs("Hello World");
-        Assert.assertEquals(-862545276, result);
+        Assert.assertEquals(expectedResult, result);
     }
 
     /*
@@ -70,7 +88,9 @@
         /*
          * Collect profiling information by running the method in the interpreter.
          */
+
         for (int i = 0; i < 10000; i++) {
+            /* Execute several times so that enough profiling information gets collected. */
             speculativeOptimization(false);
         }
 
@@ -121,13 +141,17 @@
 
     @Test
     public void testInstanceOfUsage() throws InvalidInstalledCodeException {
-        A a = new A();
+        /*
+         * Collect profiling information by running the method in the interpreter.
+         */
 
-        /* Allocate an (unsued) instance of B so that the class B gets loaded. */
+        A a = new A();
+        /* Allocate an (unused) instance of B so that the class B gets loaded. */
         @SuppressWarnings("unused")
         B b = new B();
-
+        int expectedResult = instanceOfUsage(a);
         for (int i = 0; i < 10000; i++) {
+            /* Execute several times so that enough profiling information gets collected. */
             instanceOfUsage(a);
         }
 
@@ -136,7 +160,7 @@
         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage"));
 
         int result = (int) compiledMethod.executeVarargs(a);
-        Assert.assertEquals(42, result);
+        Assert.assertEquals(expectedResult, result);
     }
 
     /*
@@ -149,9 +173,11 @@
 
     @Test
     public void testIntrinsicUsage() throws InvalidInstalledCodeException {
+        double expectedResult = intrinsicUsage(42d);
+
         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage"));
 
         double result = (double) compiledMethod.executeVarargs(42d);
-        Assert.assertEquals(Math.sin(42), result, 0);
+        Assert.assertEquals(expectedResult, result, 0);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Feb 03 17:03:19 2015 +0100
@@ -75,7 +75,7 @@
 
     /**
      * Adds a root method to the static analysis. The method must be static and must not have any
-     * parameters, because the possible types of the parametes would not be known.
+     * parameters, because the possible types of the parameters would not be known.
      */
     public void addMethod(ResolvedJavaMethod method) {
         if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) {
@@ -222,7 +222,7 @@
                      * the code before static analysis, the classes would otherwise be not loaded
                      * yet and the bytecode parser would only create a graph.
                      */
-                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault().withOmitAllExceptionEdges(true);
+                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault();
                     /*
                      * For simplicity, we ignore all exception handling during the static analysis.
                      * This is a constraint of this example code, a real static analysis needs to
@@ -311,7 +311,7 @@
      * The active element for method invocations. For {@link InvokeKind#Virtual virtual} and
      * {@link InvokeKind#Interface interface} calls, the {@link TypeFlow#getTypes() types} of this
      * node are the receiver types. When a new receiver type is added, a new callee might be added.
-     * Adding a new callee means liking the type flow of the actual parameters with the formal
+     * Adding a new callee means linking the type flow of the actual parameters with the formal
      * parameters of the callee, and linking the return value of the callee with the return value
      * state of the invocation.
      *
@@ -319,7 +319,6 @@
      * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for
      * simplicity.
      */
-
     class InvokeTypeFlow extends TypeFlow {
         private final MethodCallTargetNode callTarget;
         private final TypeFlow[] actualParameters;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Feb 03 17:03:19 2015 +0100
@@ -356,7 +356,7 @@
             try (Scope s1 = Debug.scope("BuildFrameMap")) {
                 // build frame map
                 final StackSlotAllocator allocator;
-                if (LSStackSlotAllocator.Options.EnableLSStackSlotAllocation.getValue()) {
+                if (LSStackSlotAllocator.Options.LSStackSlotAllocation.getValue()) {
                     allocator = new LSStackSlotAllocator();
                 } else {
                     allocator = new SimpleStackSlotAllocator();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Feb 03 17:03:19 2015 +0100
@@ -85,8 +85,12 @@
         }
 
         if (OptLoopTransform.getValue()) {
-            appendPhase(new LoopTransformHighPhase());
-            appendPhase(new LoopTransformLowPhase());
+            if (LoopPeeling.getValue()) {
+                appendPhase(new LoopPeelingPhase());
+            }
+            if (LoopUnswitch.getValue()) {
+                appendPhase(new LoopUnswitchingPhase());
+            }
         }
         appendPhase(new RemoveValueProxyPhase());
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Feb 03 17:03:19 2015 +0100
@@ -89,6 +89,10 @@
 
         appendPhase(new FrameStateAssignmentPhase());
 
+        if (ReassociateInvariants.getValue()) {
+            appendPhase(new ReassociateInvariantPhase());
+        }
+
         if (OptDeoptimizationGrouping.getValue()) {
             appendPhase(new DeoptimizationGroupingPhase());
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Feb 03 17:03:19 2015 +0100
@@ -166,7 +166,7 @@
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
-        startGVNNumber = clazz.getName().hashCode();
+        startGVNNumber = clazz.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/replacements/HotSpotGraphBuilderPluginsProvider.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Tue Feb 03 17:03:19 2015 +0100
@@ -29,12 +29,18 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
+/**
+ * Provider of HotSpot specific {@link GraphBuilderPlugin}s.
+ */
 @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) {
@@ -52,10 +58,5 @@
         public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
             return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name());
         }
-
-        @Override
-        public String toString() {
-            return Object.class.getName() + "." + name() + "()";
-        }
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java	Tue Feb 03 17:03:19 2015 +0100
@@ -22,41 +22,31 @@
  */
 package com.oracle.graal.java;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.type.*;
 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) {
-                assert args.length == 1;
-                ValueNode rcvr = args[0];
-                ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
-
-                boolean needsCheck = true;
-                if (objectStamp.isExactType()) {
-                    needsCheck = objectStamp.type().hasFinalizer();
-                } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
-                    // if either the declared type of receiver or the holder
-                    // can be assumed to have no finalizers
-                    Assumptions assumptions = builder.getAssumptions();
-                    if (assumptions.useOptimisticAssumptions()) {
-                        assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type());
-                        needsCheck = false;
-                    }
-                }
-
-                if (needsCheck) {
-                    builder.append(new RegisterFinalizerNode(rcvr));
+                ValueNode object = args[0];
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
                 }
                 return true;
             }
@@ -71,4 +61,50 @@
             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/GraphBuilderPhase.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Feb 03 17:03:19 2015 +0100
@@ -775,9 +775,13 @@
                     if (graphBuilderPlugins != null) {
                         GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod);
                         if (plugin != null) {
+                            int beforeStackSize = frameState.stackSize;
                             if (plugin.handleInvocation(this, args)) {
+                                // System.out.println("used plugin: " + plugin);
+                                assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize;
                                 return;
                             }
+                            assert beforeStackSize == frameState.stackSize;
                         }
                     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Feb 03 17:03:19 2015 +0100
@@ -42,14 +42,21 @@
     boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args);
 
     /**
-     * Gets the target method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])}
-     * .
+     * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} .
      */
     ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess);
 
-    static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class<?> clazz, String methodName, Class<?>... parameterTypes) {
+    /**
+     * 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>") ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getDeclaredMethod(methodName, parameterTypes));
+            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	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Tue Feb 03 17:03:19 2015 +0100
@@ -44,6 +44,7 @@
             GraphBuilderPlugin gbp = (GraphBuilderPlugin) o;
             ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess);
             GraphBuilderPlugin oldValue = map.put(target, gbp);
+            // System.out.println("registered: " + gbp);
             assert oldValue == null;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java	Tue Feb 03 17:03:19 2015 +0100
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.stackslotalloc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+
+/**
+ * Calculates the stack intervals using a worklist-based backwards data-flow analysis.
+ */
+final class FixPointIntervalBuilder {
+    private final BlockMap<BitSet> liveInMap;
+    private final BlockMap<BitSet> liveOutMap;
+    private final LIR lir;
+    private final int maxOpId;
+    private final StackInterval[] stackSlotMap;
+
+    /**
+     * The number of allocated stack slots.
+     */
+    private static final DebugMetric uninitializedSlots = Debug.metric("StackSlotAllocator[uninitializedSlots]");
+
+    FixPointIntervalBuilder(LIR lir, StackInterval[] stackSlotMap, int maxOpId) {
+        this.lir = lir;
+        this.stackSlotMap = stackSlotMap;
+        this.maxOpId = maxOpId;
+        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    void build() {
+        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+        for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
+            worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
+        }
+        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+            liveInMap.put(block, new BitSet(stackSlotMap.length));
+        }
+        while (!worklist.isEmpty()) {
+            AbstractBlock<?> block = worklist.poll();
+            processBlock(block, worklist);
+        }
+    }
+
+    /**
+     * Merge outSet with in-set of successors.
+     */
+    private boolean updateOutBlock(AbstractBlock<?> block) {
+        BitSet union = new BitSet(stackSlotMap.length);
+        block.getSuccessors().forEach(succ -> union.or(liveInMap.get(succ)));
+        BitSet outSet = liveOutMap.get(block);
+        // check if changed
+        if (outSet == null || !union.equals(outSet)) {
+            liveOutMap.put(block, union);
+            return true;
+        }
+        return false;
+    }
+
+    private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
+        if (updateOutBlock(block)) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                // get out set and mark intervals
+                BitSet outSet = liveOutMap.get(block);
+                markOutInterval(outSet, getBlockEnd(instructions));
+                printLiveSet("liveOut", outSet);
+
+                // process instructions
+                BlockClosure closure = new BlockClosure((BitSet) outSet.clone());
+                for (int i = instructions.size() - 1; i >= 0; i--) {
+                    LIRInstruction inst = instructions.get(i);
+                    closure.processInstructionBottomUp(inst);
+                }
+
+                // add predecessors to work list
+                worklist.addAll(block.getPredecessors());
+                // set in set and mark intervals
+                BitSet inSet = closure.getCurrentSet();
+                liveInMap.put(block, inSet);
+                markInInterval(inSet, getBlockBegin(instructions));
+                printLiveSet("liveIn", inSet);
+            }
+        }
+    }
+
+    private void printLiveSet(String label, BitSet liveSet) {
+        if (Debug.isLogEnabled()) {
+            try (Indent indent = Debug.logAndIndent(label)) {
+                Debug.log("%s", liveSetToString(liveSet));
+            }
+        }
+    }
+
+    private String liveSetToString(BitSet liveSet) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = liveSet.nextSetBit(0); i >= 0; i = liveSet.nextSetBit(i + 1)) {
+            StackInterval interval = getIntervalFromStackId(i);
+            sb.append(interval.getOperand()).append(" ");
+        }
+        return sb.toString();
+    }
+
+    private void markOutInterval(BitSet outSet, int blockEndOpId) {
+        for (int i = outSet.nextSetBit(0); i >= 0; i = outSet.nextSetBit(i + 1)) {
+            StackInterval interval = getIntervalFromStackId(i);
+            Debug.log("mark live operand: %s", interval.getOperand());
+            interval.addTo(blockEndOpId);
+        }
+    }
+
+    private void markInInterval(BitSet inSet, int blockFirstOpId) {
+        for (int i = inSet.nextSetBit(0); i >= 0; i = inSet.nextSetBit(i + 1)) {
+            StackInterval interval = getIntervalFromStackId(i);
+            Debug.log("mark live operand: %s", interval.getOperand());
+            interval.addFrom(blockFirstOpId);
+        }
+    }
+
+    private final class BlockClosure {
+        private final BitSet currentSet;
+
+        private BlockClosure(BitSet set) {
+            currentSet = set;
+        }
+
+        private BitSet getCurrentSet() {
+            return currentSet;
+        }
+
+        /**
+         * Process all values of an instruction bottom-up, i.e. definitions before usages. Values
+         * that start or end at the current operation are not included.
+         */
+        private void processInstructionBottomUp(LIRInstruction op) {
+            try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+                // kills
+                op.visitEachTemp(this::defConsumer);
+                op.visitEachOutput(this::defConsumer);
+
+                // gen - values that are considered alive for this state
+                op.visitEachAlive(this::useConsumer);
+                op.visitEachState(this::useConsumer);
+                // mark locations
+                // gen
+                op.visitEachInput(this::useConsumer);
+            }
+        }
+
+        /**
+         * @see InstructionValueConsumer
+         *
+         * @param inst
+         * @param operand
+         * @param mode
+         * @param flags
+         */
+        private void useConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isVirtualStackSlot(operand)) {
+                VirtualStackSlot vslot = asVirtualStackSlot(operand);
+                addUse(vslot, inst, flags);
+                Debug.log("set operand: %s", operand);
+                currentSet.set(vslot.getId());
+            }
+        }
+
+        /**
+         *
+         * @see InstructionValueConsumer
+         *
+         * @param inst
+         * @param operand
+         * @param mode
+         * @param flags
+         */
+        private void defConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isVirtualStackSlot(operand)) {
+                VirtualStackSlot vslot = asVirtualStackSlot(operand);
+                addDef(vslot, inst);
+                Debug.log("clear operand: %s", operand);
+                currentSet.clear(vslot.getId());
+            }
+
+        }
+
+        private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet<OperandFlag> flags) {
+            StackInterval interval = getOrCreateInterval(stackSlot);
+            if (flags.contains(OperandFlag.UNINITIALIZED)) {
+                // Stack slot is marked uninitialized so we have to assume it is live all
+                // the time.
+                if (Debug.isMeterEnabled() && !(interval.from() == 0 && interval.to() == maxOpId)) {
+                    uninitializedSlots.increment();
+                }
+                interval.addFrom(0);
+                interval.addTo(maxOpId);
+            } else {
+                interval.addTo(inst.id());
+            }
+        }
+
+        private void addDef(VirtualStackSlot stackSlot, LIRInstruction inst) {
+            StackInterval interval = getOrCreateInterval(stackSlot);
+            interval.addFrom(inst.id());
+        }
+
+    }
+
+    private StackInterval get(VirtualStackSlot stackSlot) {
+        return stackSlotMap[stackSlot.getId()];
+    }
+
+    private void put(VirtualStackSlot stackSlot, StackInterval interval) {
+        stackSlotMap[stackSlot.getId()] = interval;
+    }
+
+    private StackInterval getOrCreateInterval(VirtualStackSlot stackSlot) {
+        StackInterval interval = get(stackSlot);
+        if (interval == null) {
+            interval = new StackInterval(stackSlot, stackSlot.getLIRKind());
+            put(stackSlot, interval);
+        }
+        return interval;
+    }
+
+    private StackInterval getIntervalFromStackId(int id) {
+        return stackSlotMap[id];
+    }
+
+    private static int getBlockBegin(List<LIRInstruction> instructions) {
+        return instructions.get(0).id();
+    }
+
+    private static int getBlockEnd(List<LIRInstruction> instructions) {
+        return instructions.get(instructions.size() - 1).id() + 1;
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java	Tue Feb 03 17:02:15 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.stackslotalloc;
-
-import static com.oracle.graal.api.code.CodeUtil.*;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.*;
-
-public class InstructionNumberer {
-
-    private LIRInstruction[] opIdToInstructionMap;
-    private AbstractBlock<?>[] opIdToBlockMap;
-
-    /**
-     * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR
-     * instructions in a method have an index one greater than their linear-scan order predecesor
-     * with the first instruction having an index of 0.
-     */
-    private static int opIdToIndex(int opId) {
-        return opId >> 1;
-    }
-
-    /**
-     * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}.
-     *
-     * @param opId an instruction {@linkplain LIRInstruction#id id}
-     * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
-     */
-    protected LIRInstruction instructionForId(int opId) {
-        assert isEven(opId) : "opId not even";
-        LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
-        assert instr.id() == opId;
-        return instr;
-    }
-
-    /**
-     * Numbers all instructions in all blocks.
-     */
-    protected void numberInstructions(LIR lir, List<? extends AbstractBlock<?>> sortedBlocks) {
-
-        // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
-        int numInstructions = 0;
-        for (AbstractBlock<?> block : sortedBlocks) {
-            numInstructions += lir.getLIRforBlock(block).size();
-        }
-
-        // initialize with correct length
-        opIdToInstructionMap = new LIRInstruction[numInstructions];
-        opIdToBlockMap = new AbstractBlock<?>[numInstructions];
-
-        int opId = 0;
-        int index = 0;
-        for (AbstractBlock<?> block : sortedBlocks) {
-
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-
-            int numInst = instructions.size();
-            for (int j = 0; j < numInst; j++) {
-                LIRInstruction op = instructions.get(j);
-                op.setId(opId);
-
-                opIdToInstructionMap[index] = op;
-                opIdToBlockMap[index] = block;
-                assert instructionForId(opId) == op : "must match";
-
-                index++;
-                opId += 2; // numbering of lirOps by two
-            }
-        }
-        assert index == numInstructions : "must match";
-        assert (index << 1) == opId : "must match: " + (index << 1);
-    }
-
-    /**
-     * Gets the highest instruction id allocated by this object.
-     */
-    public int maxOpId() {
-        assert opIdToInstructionMap.length > 0 : "no operations";
-        return (opIdToInstructionMap.length - 1) << 1;
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Feb 03 17:03:19 2015 +0100
@@ -53,329 +53,122 @@
 
     public static class Options {
         // @formatter:off
-        @Option(help = "Enable linear scan stack slot allocation.", type = OptionType.Debug)
-        public static final OptionValue<Boolean> EnableLSStackSlotAllocation = new OptionValue<>(true);
+        @Option(help = "Use linear scan stack slot allocation.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LSStackSlotAllocation = new OptionValue<>(true);
         // @formatter:on
     }
 
-    /**
-     * The number of allocated stack slots.
-     */
-    static final DebugMetric uninitializedSlots = Debug.metric("StackSlotAllocator[uninitializedSlots]");
-
     public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
         new Allocator(res.getLIR(), builder).allocate();
     }
 
-    static final class Allocator extends InstructionNumberer {
+    private static final class Allocator {
         private final LIR lir;
         private final FrameMapBuilderTool frameMapBuilder;
         private final StackInterval[] stackSlotMap;
-        private LinkedList<StackInterval> unhandled;
-        private LinkedList<StackInterval> active;
-
-        private List<? extends AbstractBlock<?>> sortedBlocks;
+        private final PriorityQueue<StackInterval> unhandled;
+        private final PriorityQueue<StackInterval> active;
+        private final List<? extends AbstractBlock<?>> sortedBlocks;
+        private final int maxOpId;
 
         private Allocator(LIR lir, FrameMapBuilderTool frameMapBuilder) {
             this.lir = lir;
             this.frameMapBuilder = frameMapBuilder;
             this.stackSlotMap = new StackInterval[frameMapBuilder.getNumberOfStackSlots()];
+            this.sortedBlocks = lir.getControlFlowGraph().getBlocks();
+
+            // insert by from
+            this.unhandled = new PriorityQueue<>((a, b) -> a.from() - b.from());
+            // insert by to
+            this.active = new PriorityQueue<>((a, b) -> a.to() - b.to());
+
+            // step 1: number instructions
+            this.maxOpId = numberInstructions(lir, sortedBlocks);
         }
 
         private void allocate() {
-            // create block ordering
-            List<? extends AbstractBlock<?>> blocks = lir.getControlFlowGraph().getBlocks();
-            assert blocks.size() > 0;
-
-            sortedBlocks = lir.getControlFlowGraph().getBlocks();
-            numberInstructions(lir, sortedBlocks);
             Debug.dump(lir, "After StackSlot numbering");
 
             long currentFrameSize = Debug.isMeterEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0;
-            // build intervals
-            // buildIntervals();
+            // step 2: build intervals
             try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals")) {
-                buildIntervalsSlow();
+                buildIntervals();
             }
+            // step 3: verify intervals
             if (Debug.isEnabled()) {
                 verifyIntervals();
             }
             if (Debug.isDumpEnabled()) {
                 dumpIntervals("Before stack slot allocation");
             }
-            // allocate stack slots
+            // step 4: allocate stack slots
             allocateStackSlots();
             if (Debug.isDumpEnabled()) {
                 dumpIntervals("After stack slot allocation");
             }
 
-            // assign stack slots
+            // step 5: assign stack slots
             assignStackSlots();
             Debug.dump(lir, "After StackSlot assignment");
-            StackSlotAllocator.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize);
-        }
-
-        private void buildIntervalsSlow() {
-            new SlowIntervalBuilder().build();
-        }
-
-        /**
-         * Calculates the stack intervals using a worklist-based backwards data-flow analysis.
-         */
-        private final class SlowIntervalBuilder {
-            final BlockMap<BitSet> liveInMap;
-            final BlockMap<BitSet> liveOutMap;
-
-            private SlowIntervalBuilder() {
-                liveInMap = new BlockMap<>(lir.getControlFlowGraph());
-                liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
-            }
-
-            private void build() {
-                Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
-                for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
-                    worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
-                }
-                for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-                    liveInMap.put(block, new BitSet(frameMapBuilder.getNumberOfStackSlots()));
-                }
-                while (!worklist.isEmpty()) {
-                    AbstractBlock<?> block = worklist.poll();
-                    processBlock(block, worklist);
-                }
-            }
-
-            /**
-             * Merge outSet with in-set of successors.
-             */
-            private boolean updateOutBlock(AbstractBlock<?> block) {
-                BitSet union = new BitSet(frameMapBuilder.getNumberOfStackSlots());
-                block.getSuccessors().forEach(succ -> union.or(liveInMap.get(succ)));
-                BitSet outSet = liveOutMap.get(block);
-                // check if changed
-                if (outSet == null || !union.equals(outSet)) {
-                    liveOutMap.put(block, union);
-                    return true;
-                }
-                return false;
-            }
-
-            private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
-                if (updateOutBlock(block)) {
-                    try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
-                        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                        // get out set and mark intervals
-                        BitSet outSet = liveOutMap.get(block);
-                        markOutInterval(outSet, getBlockEnd(instructions));
-                        printLiveSet("liveOut", outSet);
-
-                        // process instructions
-                        BlockClosure closure = new BlockClosure((BitSet) outSet.clone());
-                        for (int i = instructions.size() - 1; i >= 0; i--) {
-                            LIRInstruction inst = instructions.get(i);
-                            closure.processInstructionBottomUp(inst);
-                        }
-
-                        // add predecessors to work list
-                        worklist.addAll(block.getPredecessors());
-                        // set in set and mark intervals
-                        BitSet inSet = closure.getCurrentSet();
-                        liveInMap.put(block, inSet);
-                        markInInterval(inSet, getBlockBegin(instructions));
-                        printLiveSet("liveIn", inSet);
-                    }
-                }
-            }
-
-            private void printLiveSet(String label, BitSet liveSet) {
-                if (Debug.isLogEnabled()) {
-                    try (Indent indent = Debug.logAndIndent(label)) {
-                        Debug.log("%s", liveSetToString(liveSet));
-                    }
-                }
-            }
-
-            private String liveSetToString(BitSet liveSet) {
-                StringBuilder sb = new StringBuilder();
-                for (int i = liveSet.nextSetBit(0); i >= 0; i = liveSet.nextSetBit(i + 1)) {
-                    StackInterval interval = getIntervalFromStackId(i);
-                    sb.append(interval.getOperand()).append(" ");
-                }
-                return sb.toString();
-            }
-
-            protected void markOutInterval(BitSet outSet, int blockEndOpId) {
-                for (int i = outSet.nextSetBit(0); i >= 0; i = outSet.nextSetBit(i + 1)) {
-                    StackInterval interval = getIntervalFromStackId(i);
-                    Debug.log("mark live operand: %s", interval.getOperand());
-                    interval.addTo(blockEndOpId);
-                }
-            }
-
-            protected void markInInterval(BitSet inSet, int blockFirstOpId) {
-                for (int i = inSet.nextSetBit(0); i >= 0; i = inSet.nextSetBit(i + 1)) {
-                    StackInterval interval = getIntervalFromStackId(i);
-                    Debug.log("mark live operand: %s", interval.getOperand());
-                    interval.addFrom(blockFirstOpId);
-                }
-            }
-
-            private final class BlockClosure {
-                private final BitSet currentSet;
-
-                private BlockClosure(BitSet set) {
-                    currentSet = set;
-                }
-
-                private BitSet getCurrentSet() {
-                    return currentSet;
-                }
-
-                /**
-                 * Process all values of an instruction bottom-up, i.e. definitions before usages.
-                 * Values that start or end at the current operation are not included.
-                 */
-                private void processInstructionBottomUp(LIRInstruction op) {
-                    try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
-                        // kills
-                        op.visitEachTemp(this::defConsumer);
-                        op.visitEachOutput(this::defConsumer);
-                        // forEachDestroyedCallerSavedRegister(op, this::defConsumer);
-
-                        // gen - values that are considered alive for this state
-                        op.visitEachAlive(this::useConsumer);
-                        op.visitEachState(this::useConsumer);
-                        // mark locations
-                        // gen
-                        op.visitEachInput(this::useConsumer);
-                    }
-                }
-
-                /**
-                 * @see InstructionValueConsumer
-                 *
-                 * @param inst
-                 * @param operand
-                 * @param mode
-                 * @param flags
-                 */
-                private void useConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVirtualStackSlot(operand)) {
-                        VirtualStackSlot vslot = asVirtualStackSlot(operand);
-                        addUse(vslot, inst, flags);
-                        Debug.log("set operand: %s", operand);
-                        currentSet.set(vslot.getId());
-                    }
-                }
-
-                /**
-                 *
-                 * @see InstructionValueConsumer
-                 *
-                 * @param inst
-                 * @param operand
-                 * @param mode
-                 * @param flags
-                 */
-                private void defConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVirtualStackSlot(operand)) {
-                        VirtualStackSlot vslot = asVirtualStackSlot(operand);
-                        addDef(vslot, inst);
-                        Debug.log("clear operand: %s", operand);
-                        currentSet.clear(vslot.getId());
-                    }
-
-                }
-
-                private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet<OperandFlag> flags) {
-                    StackInterval interval = getOrCreateInterval(stackSlot);
-                    if (flags.contains(OperandFlag.UNINITIALIZED)) {
-                        // Stack slot is marked uninitialized so we have to assume it is live all
-                        // the time.
-                        if (Debug.isMeterEnabled() && !(interval.from() == 0 && interval.to() == maxOpId())) {
-                            uninitializedSlots.increment();
-                        }
-                        interval.addDef(0);
-                        interval.addUse(maxOpId());
-                    } else {
-                        interval.addUse(inst.id());
-                    }
-                }
-
-                private void addDef(VirtualStackSlot stackSlot, LIRInstruction inst) {
-                    StackInterval interval = getOrCreateInterval(stackSlot);
-                    interval.addDef(inst.id());
-                }
-
+            if (Debug.isMeterEnabled()) {
+                StackSlotAllocator.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize);
             }
         }
 
-        private static int getBlockBegin(List<LIRInstruction> instructions) {
-            return instructions.get(0).id();
-        }
+        // ====================
+        // step 1: number instructions
+        // ====================
+
+        /**
+         * Numbers all instructions in all blocks.
+         *
+         * @return The id of the last operation.
+         */
+        private static int numberInstructions(LIR lir, List<? extends AbstractBlock<?>> sortedBlocks) {
+            int opId = 0;
+            int index = 0;
+            for (AbstractBlock<?> block : sortedBlocks) {
 
-        private static int getBlockEnd(List<LIRInstruction> instructions) {
-            return instructions.get(instructions.size() - 1).id() + 1;
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+                int numInst = instructions.size();
+                for (int j = 0; j < numInst; j++) {
+                    LIRInstruction op = instructions.get(j);
+                    op.setId(opId);
+
+                    index++;
+                    opId += 2; // numbering of lirOps by two
+                }
+            }
+            assert (index << 1) == opId : "must match: " + (index << 1);
+            return opId - 2;
         }
 
-        private StackInterval getOrCreateInterval(VirtualStackSlot stackSlot) {
-            StackInterval interval = get(stackSlot);
-            if (interval == null) {
-                interval = new StackInterval(stackSlot, stackSlot.getLIRKind());
-                put(stackSlot, interval);
-            }
-            return interval;
+        // ====================
+        // step 2: build intervals
+        // ====================
+
+        private void buildIntervals() {
+            new FixPointIntervalBuilder(lir, stackSlotMap, maxOpId()).build();
         }
 
-        private StackInterval get(VirtualStackSlot stackSlot) {
-            return stackSlotMap[stackSlot.getId()];
-        }
-
-        private StackInterval getIntervalFromStackId(int id) {
-            return stackSlotMap[id];
-        }
-
-        private void put(VirtualStackSlot stackSlot, StackInterval interval) {
-            stackSlotMap[stackSlot.getId()] = interval;
-        }
+        // ====================
+        // step 3: verify intervals
+        // ====================
 
         private void verifyIntervals() {
             forEachInterval(interval -> {
-                assert interval.verify(this);
+                assert interval.verify(maxOpId());
             });
         }
 
-        private void forEachInterval(Consumer<StackInterval> proc) {
-            for (StackInterval interval : stackSlotMap) {
-                if (interval != null) {
-                    proc.accept(interval);
-                }
-            }
-        }
-
-        public void dumpIntervals(String label) {
-            Debug.dump(stackSlotMap, label);
-        }
-
-        private void createUnhandled() {
-            unhandled = new LinkedList<>();
-            active = new LinkedList<>();
-            forEachInterval(this::insertSortedByFrom);
-        }
-
-        private void insertSortedByFrom(StackInterval interval) {
-            unhandled.add(interval);
-            unhandled.sort((a, b) -> a.from() - b.from());
-        }
-
-        private void insertSortedByTo(StackInterval interval) {
-            active.add(interval);
-            active.sort((a, b) -> a.to() - b.to());
-        }
+        // ====================
+        // step 4: allocate stack slots
+        // ====================
 
         private void allocateStackSlots() {
-            // create interval lists
-            createUnhandled();
+            // create unhandled lists
+            forEachInterval(unhandled::add);
 
             for (StackInterval current = activateNext(); current != null; current = activateNext()) {
                 try (Indent indent = Debug.logAndIndent("allocate %s", current)) {
@@ -395,7 +188,7 @@
                 StackSlotAllocator.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots()));
                 StackSlotAllocator.allocatedSlots.increment();
             } else {
-                assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpexted VirtualStackSlot type: " + virtualSlot;
+                assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpected VirtualStackSlot type: " + virtualSlot;
                 StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot);
                 if (slot != null) {
                     /*
@@ -440,58 +233,108 @@
             }
         }
 
-        private EnumMap<SlotSize, LinkedList<StackSlot>> freeSlots = new EnumMap<>(SlotSize.class);
+        private EnumMap<SlotSize, Deque<StackSlot>> freeSlots;
+
+        /**
+         * @return The list of free stack slots for {@code size} or {@code null} if there is none.
+         */
+        private Deque<StackSlot> getOrNullFreeSlots(SlotSize size) {
+            if (freeSlots == null) {
+                return null;
+            }
+            return freeSlots.get(size);
+        }
 
+        /**
+         * @return the list of free stack slots for {@code size}. If there is none a list is
+         *         created.
+         */
+        private Deque<StackSlot> getOrInitFreeSlots(SlotSize size) {
+            assert size != SlotSize.Illegal;
+            Deque<StackSlot> freeList;
+            if (freeSlots != null) {
+                freeList = freeSlots.get(size);
+            } else {
+                freeSlots = new EnumMap<>(SlotSize.class);
+                freeList = null;
+            }
+            if (freeList == null) {
+                freeList = new ArrayDeque<>();
+                freeSlots.put(size, freeList);
+            }
+            assert freeList != null;
+            return freeList;
+        }
+
+        /**
+         * Gets a free stack slot for {@code slot} or {@code null} if there is none.
+         */
         private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) {
             assert slot != null;
             SlotSize size = forKind(slot.getLIRKind());
-            LinkedList<StackSlot> freeList = size == SlotSize.Illegal ? null : freeSlots.get(size);
+            if (size == SlotSize.Illegal) {
+                return null;
+            }
+            Deque<StackSlot> freeList = getOrNullFreeSlots(size);
             if (freeList == null) {
                 return null;
             }
-            return freeList.pollFirst();
+            return freeList.pollLast();
         }
 
+        /**
+         * Adds a stack slot to the list of free slots.
+         */
         private void freeSlot(StackSlot slot) {
             SlotSize size = forKind(slot.getLIRKind());
             if (size == SlotSize.Illegal) {
                 return;
             }
-            LinkedList<StackSlot> freeList = freeSlots.get(size);
-            if (freeList == null) {
-                freeList = new LinkedList<>();
-                freeSlots.put(size, freeList);
-            }
-            freeList.add(slot);
+            getOrInitFreeSlots(size).addLast(slot);
         }
 
+        /**
+         * Gets the next unhandled interval and finishes handled intervals.
+         */
         private StackInterval activateNext() {
             if (unhandled.isEmpty()) {
                 return null;
             }
-            StackInterval next = unhandled.pollFirst();
+            StackInterval next = unhandled.poll();
+            // finish handled intervals
             for (int id = next.from(); activePeekId() < id;) {
-                finished(active.pollFirst());
+                finished(active.poll());
             }
-            Debug.log("activte %s", next);
-            insertSortedByTo(next);
+            Debug.log("active %s", next);
+            active.add(next);
             return next;
         }
 
+        /**
+         * Gets the lowest {@link StackInterval#to() end position} of all active intervals. If there
+         * is none {@link Integer#MAX_VALUE} is returned.
+         */
         private int activePeekId() {
-            StackInterval first = active.peekFirst();
+            StackInterval first = active.peek();
             if (first == null) {
                 return Integer.MAX_VALUE;
             }
             return first.to();
         }
 
+        /**
+         * Finishes {@code interval} by adding its location to the list of free stack slots.
+         */
         private void finished(StackInterval interval) {
             StackSlot location = interval.location();
             Debug.log("finished %s (freeing %s)", interval, location);
             freeSlot(location);
         }
 
+        // ====================
+        // step 5: assign stack slots
+        // ====================
+
         private void assignStackSlots() {
             for (AbstractBlock<?> block : sortedBlocks) {
                 lir.getLIRforBlock(block).forEach(op -> {
@@ -520,5 +363,33 @@
             }
             return value;
         }
+
+        // ====================
+        //
+        // ====================
+
+        /**
+         * Gets the highest instruction id.
+         */
+        private int maxOpId() {
+            return maxOpId;
+        }
+
+        private StackInterval get(VirtualStackSlot stackSlot) {
+            return stackSlotMap[stackSlot.getId()];
+        }
+
+        private void forEachInterval(Consumer<StackInterval> proc) {
+            for (StackInterval interval : stackSlotMap) {
+                if (interval != null) {
+                    proc.accept(interval);
+                }
+            }
+        }
+
+        private void dumpIntervals(String label) {
+            Debug.dump(stackSlotMap, label);
+        }
+
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java	Tue Feb 03 17:03:19 2015 +0100
@@ -24,9 +24,8 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
 
-public class StackInterval {
+public final class StackInterval {
 
     private static final int INVALID_START = Integer.MAX_VALUE;
     private static final int INVALID_END = Integer.MIN_VALUE;
@@ -34,25 +33,16 @@
     private final LIRKind kind;
     private int from = INVALID_START;
     private int to = INVALID_END;
-    private final StackUsePosList usePos;
     private StackSlot location;
 
-    public enum UseType {
-        // Prefixes for c1viz
-        M_USE,
-        S_DEF
-    }
-
     public StackInterval(VirtualStackSlot operand, LIRKind kind) {
         this.operand = operand;
         this.kind = kind;
-        this.usePos = new StackUsePosList();
     }
 
-    public boolean verify(LSStackSlotAllocator.Allocator allocator) {
-        assert usePosList().verify();
-        // maxOpId + 1 it the last position in the last block (i.e. the "write position")
-        assert from >= 0 && to <= allocator.maxOpId() + 1 : String.format("from %d, to %d, maxOpId %d", from, to, allocator.maxOpId());
+    public boolean verify(int maxOpId) {
+        // maxOpId + 1 is the last position in the last block (i.e. the "write position")
+        assert 0 <= from && from <= to && to <= maxOpId + 1 : String.format("from %d, to %d, maxOpId %d", from, to, maxOpId);
         return true;
     }
 
@@ -60,18 +50,6 @@
         return operand;
     }
 
-    public void addUse(int opId) {
-        addTo(opId);
-        Debug.log("Adding use pos: %d", opId);
-        usePos.add(opId, UseType.M_USE);
-    }
-
-    public void addDef(int opId) {
-        addFrom(opId);
-        Debug.log("Adding def pos: %d", opId);
-        usePos.add(opId, UseType.S_DEF);
-    }
-
     public void addTo(int opId) {
         if (opId >= to) {
             to = opId;
@@ -100,10 +78,6 @@
         this.location = location;
     }
 
-    public StackInterval locationHint() {
-        return null;
-    }
-
     public int from() {
         return from;
     }
@@ -112,10 +86,6 @@
         return to;
     }
 
-    public StackUsePosList usePosList() {
-        return usePos;
-    }
-
     public void fixFrom() {
         if (from == INVALID_START) {
             from = 0;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java	Tue Feb 03 17:02:15 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.stackslotalloc;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.stackslotalloc.StackInterval.*;
-
-public class StackUsePosList {
-
-    LinkedList<Integer> usePosList;
-    LinkedList<UseType> typeList;
-
-    StackUsePosList() {
-        this.usePosList = new LinkedList<>();
-        this.typeList = new LinkedList<>();
-    }
-
-    public int size() {
-        return usePosList.size();
-    }
-
-    public int usePos(int i) {
-        return usePosList.get(i);
-    }
-
-    public void add(int opId, UseType type) {
-        if (usePosList.isEmpty() || opId <= usePosList.getLast()) {
-            usePosList.add(opId);
-            typeList.add(type);
-        } else if (opId >= usePosList.getFirst()) {
-            usePosList.addFirst(opId);
-            typeList.addFirst(type);
-        } else {
-            int size = usePosList.size();
-
-            assert size >= 2 : "Should be handled by the cases above";
-            assert size == typeList.size() : "types and use pos out of sync";
-
-            ListIterator<Integer> posIt = usePosList.listIterator(size - 1);
-            ListIterator<UseType> typeIt = typeList.listIterator(size - 1);
-
-            // we start with size-2 because we know it will not inserted at the end
-            while (posIt.hasPrevious()) {
-                assert posIt.nextIndex() == typeIt.nextIndex();
-                int current = posIt.previous();
-
-                if (current >= opId) {
-                    posIt.next();
-                    posIt.add(opId);
-                    typeIt.add(type);
-                    assert verify();
-                    return;
-                }
-                typeIt.previous();
-            }
-            GraalInternalError.shouldNotReachHere(String.format("Unable to insert %d into %s", opId, usePosList));
-        }
-    }
-
-    public UseType getType(int i) {
-        return typeList.get(i);
-    }
-
-    @Override
-    public String toString() {
-        return usePosList.toString() + System.lineSeparator() + typeList.toString();
-    }
-
-    public boolean verify() {
-        int prev = -1;
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            int current = usePosList.get(i);
-            assert prev <= current : String.format("use positions not sorted: %d after %d", current, prev);
-            prev = current;
-        }
-        return true;
-    }
-
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Feb 03 17:03:19 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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java	Tue Feb 03 17:03:19 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2012, 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.loop.phases;
+
+import java.util.function.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+public class LoopPeelingPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
+            LoopsData data = new LoopsData(graph);
+            for (LoopEx loop : data.outerFirst()) {
+                if (LoopPolicies.shouldPeel(loop, probabilities)) {
+                    Debug.log("Peeling %s", loop);
+                    LoopTransformations.peel(loop);
+                    Debug.dump(graph, "After peeling %s", loop);
+                }
+            }
+            data.deleteUnusedNodes();
+        }
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Tue Feb 03 17:02:15 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, 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.loop.phases;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import java.util.function.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.loop.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-
-public class LoopTransformHighPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            if (LoopPeeling.getValue()) {
-                ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
-                LoopsData data = new LoopsData(graph);
-                for (LoopEx loop : data.outerFirst()) {
-                    if (LoopPolicies.shouldPeel(loop, probabilities)) {
-                        Debug.log("Peeling %s", loop);
-                        LoopTransformations.peel(loop);
-                        Debug.dump(graph, "After peeling %s", loop);
-                    }
-                }
-                data.deleteUnusedNodes();
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Tue Feb 03 17:02:15 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, 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.loop.phases;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.loop.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-
-public class LoopTransformLowPhase extends Phase {
-
-    private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
-    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            if (ReassociateInvariants.getValue()) {
-                final LoopsData dataReassociate = new LoopsData(graph);
-                try (Scope s = Debug.scope("ReassociateInvariants")) {
-                    for (LoopEx loop : dataReassociate.loops()) {
-                        loop.reassociateInvariants();
-                    }
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-                dataReassociate.deleteUnusedNodes();
-            }
-            if (LoopUnswitch.getValue()) {
-                boolean unswitched;
-                do {
-                    unswitched = false;
-                    final LoopsData dataUnswitch = new LoopsData(graph);
-                    for (LoopEx loop : dataUnswitch.loops()) {
-                        if (LoopPolicies.shouldTryUnswitch(loop)) {
-                            List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
-                            if (controlSplits != null) {
-                                UNSWITCH_CANDIDATES.increment();
-                                if (LoopPolicies.shouldUnswitch(loop, controlSplits)) {
-                                    if (Debug.isLogEnabled()) {
-                                        logUnswitch(loop, controlSplits);
-                                    }
-                                    LoopTransformations.unswitch(loop, controlSplits);
-                                    UNSWITCHED.increment();
-                                    unswitched = true;
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                } while (unswitched);
-            }
-        }
-    }
-
-    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
-        StringBuilder sb = new StringBuilder("Unswitching ");
-        sb.append(loop).append(" at ");
-        for (ControlSplitNode controlSplit : controlSplits) {
-            sb.append(controlSplit).append(" [");
-            NodePosIterator it = controlSplit.successors().iterator();
-            while (it.hasNext()) {
-                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
-                if (it.hasNext()) {
-                    sb.append(", ");
-                }
-            }
-            sb.append("]");
-        }
-        Debug.log("%s", sb);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Tue Feb 03 17:03:19 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2012, 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.loop.phases;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class LoopUnswitchingPhase extends Phase {
+
+    private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
+    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            boolean unswitched;
+            do {
+                unswitched = false;
+                final LoopsData dataUnswitch = new LoopsData(graph);
+                for (LoopEx loop : dataUnswitch.loops()) {
+                    if (LoopPolicies.shouldTryUnswitch(loop)) {
+                        List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
+                        if (controlSplits != null) {
+                            UNSWITCH_CANDIDATES.increment();
+                            if (LoopPolicies.shouldUnswitch(loop, controlSplits)) {
+                                if (Debug.isLogEnabled()) {
+                                    logUnswitch(loop, controlSplits);
+                                }
+                                LoopTransformations.unswitch(loop, controlSplits);
+                                UNSWITCHED.increment();
+                                unswitched = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+            } while (unswitched);
+        }
+    }
+
+    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
+        StringBuilder sb = new StringBuilder("Unswitching ");
+        sb.append(loop).append(" at ");
+        for (ControlSplitNode controlSplit : controlSplits) {
+            sb.append(controlSplit).append(" [");
+            NodePosIterator it = controlSplit.successors().iterator();
+            while (it.hasNext()) {
+                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
+                if (it.hasNext()) {
+                    sb.append(", ");
+                }
+            }
+            sb.append("]");
+        }
+        Debug.log("%s", sb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java	Tue Feb 03 17:03:19 2015 +0100
@@ -0,0 +1,47 @@
+/*
+ * 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.loop.phases;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class ReassociateInvariantPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            final LoopsData dataReassociate = new LoopsData(graph);
+            try (Scope s = Debug.scope("ReassociateInvariants")) {
+                for (LoopEx loop : dataReassociate.loops()) {
+                    loop.reassociateInvariants();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            dataReassociate.deleteUnusedNodes();
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Feb 03 17:03:19 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	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Tue Feb 03 17:03:19 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/debug/ControlFlowAnchorNode.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Tue Feb 03 17:03:19 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.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue Feb 03 17:03:19 2015 +0100
@@ -56,27 +56,31 @@
         gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(getValue()));
     }
 
+    /**
+     * Determines if the compiler should emit code to test whether a given object has a finalizer
+     * that must be registered with the runtime upon object initialization.
+     */
+    public static boolean mayHaveFinalizer(ValueNode object, Assumptions assumptions) {
+        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+        if (objectStamp.isExactType()) {
+            return objectStamp.type().hasFinalizer();
+        } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
+            // if either the declared type of receiver or the holder
+            // can be assumed to have no finalizers
+            if (assumptions.useOptimisticAssumptions()) {
+                assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type());
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (!(forValue.stamp() instanceof ObjectStamp)) {
             return this;
         }
-
-        ObjectStamp objectStamp = (ObjectStamp) forValue.stamp();
-
-        boolean needsCheck = true;
-        if (objectStamp.isExactType()) {
-            needsCheck = objectStamp.type().hasFinalizer();
-        } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
-            // if either the declared type of receiver or the holder
-            // can be assumed to have no finalizers
-            if (tool.assumptions().useOptimisticAssumptions()) {
-                tool.assumptions().recordNoFinalizableSubclassAssumption(objectStamp.type());
-                needsCheck = false;
-            }
-        }
-
-        if (!needsCheck) {
+        if (!mayHaveFinalizer(forValue, tool.assumptions())) {
             return null;
         }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Tue Feb 03 17:03:19 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.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Feb 03 17:03:19 2015 +0100
@@ -582,22 +582,12 @@
             out.printf("\"[%s|%c]\"", interval.getOperand(), interval.getOperand().getKind().getTypeChar());
         }
 
-        StackInterval hint = interval.locationHint();
-        out.printf("%s %s ", interval.getOperand(), hint != null ? hint.getOperand() : -1);
+        out.printf("%s -1 ", interval.getOperand());
 
         out.printf("[%d, %d[", interval.from(), interval.to());
 
-        // print use positions
-        int prev = -1;
-        StackUsePosList usePosList = interval.usePosList();
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            assert prev <= usePosList.usePos(i) : "use positions not sorted";
-            out.printf("%d %s ", usePosList.usePos(i), usePosList.getType(i));
-            prev = usePosList.usePos(i);
-        }
-
         // print spill state
-        out.printf(" \"%s\"", "NOT_SUPPORTED");
+        out.printf(" \"NOT_SUPPORTED\"");
         out.println();
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Feb 03 17:03:19 2015 +0100
@@ -137,49 +137,20 @@
             HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
 
             // EA frame and clean up.
-            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);
-            }
-
-            // to make frame propagations visible retry expandTree
-            while (expandTree(graph, assumptions, expansionLogger)) {
+            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);
             }
 
-            for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
-                Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
-                throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
-            }
-
-            new VerifyNoIntrinsicsLeftPhase().apply(graph, false);
-            for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
-                materializeNode.replaceAtUsages(materializeNode.getFrame());
-                graph.removeFixed(materializeNode);
-            }
-            for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
-                if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
-                    VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
-                    virtualOnlyInstanceNode.setAllowMaterialization(true);
-                } else if (virtualObjectNode instanceof VirtualInstanceNode) {
-                    VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode;
-                    ResolvedJavaType type = virtualInstanceNode.type();
-                    if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) {
-                        virtualInstanceNode.setIdentity(false);
-                    }
-                }
-            }
+            postPartialEvaluation(graph);
 
         } catch (Throwable e) {
             throw Debug.handle(e);
@@ -188,6 +159,26 @@
         return graph;
     }
 
+    private static void postPartialEvaluation(final StructuredGraph graph) {
+        NeverPartOfCompilationNode.verifyNotFoundIn(graph);
+        for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
+            materializeNode.replaceAtUsages(materializeNode.getFrame());
+            graph.removeFixed(materializeNode);
+        }
+        for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
+            if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
+                VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
+                virtualOnlyInstanceNode.setAllowMaterialization(true);
+            } else if (virtualObjectNode instanceof VirtualInstanceNode) {
+                VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode;
+                ResolvedJavaType type = virtualInstanceNode.type();
+                if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) {
+                    virtualInstanceNode.setIdentity(false);
+                }
+            }
+        }
+    }
+
     private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) {
         ParameterNode thisNode = graph.getParameter(0);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Feb 03 17:03:19 2015 +0100
@@ -176,5 +176,8 @@
 
     @Option(help = "Print additional more verbose Truffle compilation statistics at the end of a run.", type = OptionType.Debug)
     public static final OptionValue<Boolean> TruffleCompilationStatisticDetails = new OptionValue<>(false);
+
+    @Option(help = "Experimental new version of the partial evaluator.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> FastPE = new OptionValue<>(false);
     // @formatter:on
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Tue Feb 03 17:03:19 2015 +0100
@@ -144,7 +144,12 @@
     }
 
     public TruffleInliningDecision findByCall(OptimizedDirectCallNode callNode) {
-        return getCallSites().stream().filter(c -> c.getProfile().getCallNode() == callNode).findFirst().orElse(null);
+        for (TruffleInliningDecision d : getCallSites()) {
+            if (d.getProfile().getCallNode() == callNode) {
+                return d;
+            }
+        }
+        return null;
     }
 
     /**
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Tue Feb 03 17:02:15 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Tue Feb 03 17:03:19 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -44,4 +45,11 @@
     public final String getMessage() {
         return message + " " + arguments.toString();
     }
+
+    public static void verifyNotFoundIn(final StructuredGraph graph) {
+        for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
+            Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
+            throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
+        }
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java	Tue Feb 03 17:02:15 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.phases;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.frame.*;
-
-/**
- * Verification phase for checking that no frame intrinsic nodes introduced by the
- * {@link PartialEvaluator} are still in the graph.
- */
-public class VerifyNoIntrinsicsLeftPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        verifyNoInstanceLeft(graph, NewFrameNode.class);
-    }
-
-    public static <T extends Node & IterableNodeType> void verifyNoInstanceLeft(StructuredGraph graph, Class<T> clazz) {
-        if (graph.getNodes(clazz).count() != 0) {
-            throw new VerificationError("Found unexpected node(s): %s", graph.getNodes(clazz));
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Tue Feb 03 17:03:19 2015 +0100
@@ -0,0 +1,134 @@
+/*
+ * 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.truffle.substitutions;
+
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.truffle.nodes.frame.*;
+import com.oracle.truffle.api.*;
+
+/**
+ * Provider of {@link GraphBuilderPlugin}s for Truffle classes.
+ */
+@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));
+                return true;
+            }
+        },
+        inCompiledCode() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(ConstantNode.forBoolean(true));
+                return true;
+            }
+        },
+        transferToInterpreter() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        },
+        transferToInterpreterAndInvalidate() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        },
+        interpreterOnly(Runnable.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                return true;
+            }
+        },
+        interpreterOnly$(Callable.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                return true;
+            }
+        },
+        injectBranchProbability(double.class, boolean.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                ValueNode probability = args[0];
+                ValueNode condition = args[1];
+                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];
+                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()) {
+                    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]));
+                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	Tue Feb 03 17:02:15 2015 +0100
+++ b/mxtool/mx.py	Tue Feb 03 17:03:19 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):