changeset 19052:db390d92bb16

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 31 Jan 2015 19:03:33 +0100
parents 687479c0cd3e (current diff) 75da87c96605 (diff)
children fa4e9a76a5ed
files graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappable.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappingTool.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleStackSlotAllocator.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/StackSlotAllocator.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java
diffstat 87 files changed, 3988 insertions(+), 650 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Wed Jan 28 15:07:54 2015 +0100
+++ b/CHANGELOG.md	Sat Jan 31 19:03:33 2015 +0100
@@ -6,6 +6,7 @@
 ## `tip`
 ### Graal
 * Add utilities ModifiersProvider#isConcrete, ResolvedJavaMethod#hasBytecodes, ResolvedJavaMethod#hasReceiver to Graal API.
+* Add `GraalDirectives` API, containing methods to influence compiler behavior for unittests and microbenchmarks.
 * ...
 
 ### Truffle
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java	Sat Jan 31 19:03:33 2015 +0100
@@ -44,7 +44,7 @@
 
     @Override
     public String toString() {
-        return "vstack(" + id + ")" + getKindSuffix();
+        return "vstack:" + id + getKindSuffix();
     }
 
     @Override
--- /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/BlackholeDirectiveTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,138 @@
+/*
+ * 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 org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Tests for {@link GraalDirectives#blackhole}.
+ *
+ * There are two snippets for each kind:
+ * <ul>
+ * <li>blackhole&lt;Kind&gt;Snippet verifies that dead code elimination is prevented by the
+ * blackhole directive.
+ * <li>&lt;kind&gt;Snippet verifies that dead code elimination does happen if the blackhole
+ * directive is not there.
+ * </ul>
+ *
+ */
+public class BlackholeDirectiveTest extends GraalCompilerTest {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    private @interface BlackholeSnippet {
+        boolean expectParameterUsage();
+    }
+
+    @BlackholeSnippet(expectParameterUsage = false)
+    public static int booleanSnippet(int arg) {
+        boolean b = arg > 3;
+        if (b) {
+            return 1;
+        } else {
+            return 1;
+        }
+    }
+
+    @BlackholeSnippet(expectParameterUsage = true)
+    public static int blackholeBooleanSnippet(int arg) {
+        boolean b = arg > 3;
+        GraalDirectives.blackhole(b);
+        if (b) {
+            return 1;
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testBoolean() {
+        test("booleanSnippet", 5);
+        test("blackholeBooleanSnippet", 5);
+    }
+
+    @BlackholeSnippet(expectParameterUsage = false)
+    public static int intSnippet(int arg) {
+        int x = 42 + arg;
+        return x - arg;
+    }
+
+    @BlackholeSnippet(expectParameterUsage = true)
+    public static int blackholeIntSnippet(int arg) {
+        int x = 42 + arg;
+        GraalDirectives.blackhole(x);
+        return x - arg;
+    }
+
+    @Test
+    public void testInt() {
+        test("intSnippet", 17);
+        test("blackholeIntSnippet", 17);
+    }
+
+    private static class Dummy {
+        private int x = 42;
+    }
+
+    @BlackholeSnippet(expectParameterUsage = false)
+    public static int objectSnippet(int arg) {
+        Dummy obj = new Dummy();
+        int ret = obj.x;
+        obj.x = arg;
+        return ret;
+    }
+
+    @BlackholeSnippet(expectParameterUsage = true)
+    public static int blackholeObjectSnippet(int arg) {
+        Dummy obj = new Dummy();
+        int ret = obj.x;
+        obj.x = arg;
+        GraalDirectives.blackhole(obj);
+        return ret;
+    }
+
+    @Test
+    public void testObject() {
+        test("objectSnippet", 37);
+        test("blackholeObjectSnippet", 37);
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class);
+        ParameterNode arg = graph.getParameter(0);
+        if (snippet.expectParameterUsage()) {
+            Assert.assertNotNull("couldn't find ParameterNode(0)", arg);
+            Assert.assertFalse("expected usages of " + arg, arg.hasNoUsages());
+        } else {
+            Assert.assertTrue("expected no usages of ParameterNode", arg == null || arg.hasNoUsages());
+        }
+        return true;
+    }
+}
--- /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/DeoptimizeDirectiveTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,92 @@
+/*
+ * 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 org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+
+public class DeoptimizeDirectiveTest extends GraalCompilerTest {
+
+    public static boolean inCompiledCode() {
+        return GraalDirectives.inCompiledCode();
+    }
+
+    @Test
+    public void testInCompiledCode() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("inCompiledCode");
+
+        Result interpreted = executeExpected(method, null);
+        assertEquals(new Result(false, null), interpreted);
+
+        Result compiled = executeActual(method, null);
+        assertEquals(new Result(true, null), compiled);
+    }
+
+    public static boolean deoptimizeSnippet() {
+        GraalDirectives.deoptimize();
+        return GraalDirectives.inCompiledCode(); // should always return false
+    }
+
+    public static boolean deoptimizeAndInvalidateSnippet() {
+        GraalDirectives.deoptimizeAndInvalidate();
+        return GraalDirectives.inCompiledCode(); // should always return false
+    }
+
+    @Test
+    public void testDeoptimize() {
+        test("deoptimizeSnippet");
+    }
+
+    private boolean testDeoptimizeCheckValid(ResolvedJavaMethod method) {
+        Result expected = executeExpected(method, null);
+
+        InstalledCode code = getCode(method);
+        Result actual;
+        try {
+            actual = new Result(code.executeVarargs(), null);
+        } catch (Throwable e) {
+            actual = new Result(null, e);
+        }
+
+        assertEquals(expected, actual);
+        return code.isValid();
+    }
+
+    @Test
+    public void testDeoptimizeAndInvalidate() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeAndInvalidateSnippet");
+        boolean valid = testDeoptimizeCheckValid(method);
+        Assert.assertFalse("code should be invalidated", valid);
+    }
+
+    @Test
+    public void testDeoptimizeDontInvalidate() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeSnippet");
+        boolean valid = testDeoptimizeCheckValid(method);
+        Assert.assertTrue("code should still be valid", valid);
+    }
+}
--- /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/IterationDirectiveTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.directives.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+
+public class IterationDirectiveTest extends GraalCompilerTest {
+
+    public static int loopFrequencySnippet(int arg) {
+        int x = arg;
+        while (GraalDirectives.injectIterationCount(128, x > 1)) {
+            GraalDirectives.controlFlowAnchor(); // prevent loop peeling or unrolling
+            if (x % 2 == 0) {
+                x /= 2;
+            } else {
+                x = 3 * x + 1;
+            }
+        }
+        return x;
+    }
+
+    @Test
+    public void testLoopFrequency() {
+        test("loopFrequencySnippet", 7);
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        NodeIterable<LoopBeginNode> loopBeginNodes = graph.getNodes(LoopBeginNode.class);
+        Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count());
+
+        LoopBeginNode loopBeginNode = loopBeginNodes.first();
+        Assert.assertEquals("loop frequency of " + loopBeginNode, 128, loopBeginNode.loopFrequency(), 0);
+
+        return true;
+    }
+}
--- /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/OpaqueDirectiveTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,131 @@
+/*
+ * 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 org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+
+/**
+ * Tests for {@link GraalDirectives#opaque}.
+ *
+ * There are two snippets for each kind:
+ * <ul>
+ * <li>opaque&lt;Kind&gt;Snippet verifies that constant folding is prevented by the opaque
+ * directive.
+ * <li>&lt;kind&gt;Snippet verifies that constant folding does happen if the opaque directive is not
+ * there.
+ * </ul>
+ *
+ */
+public class OpaqueDirectiveTest extends GraalCompilerTest {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    private @interface OpaqueSnippet {
+        Class<?> expectedReturnNode();
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static boolean booleanSnippet() {
+        return 5 > 3;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConditionalNode.class)
+    public static boolean opaqueBooleanSnippet() {
+        return 5 > GraalDirectives.opaque(3);
+    }
+
+    @Test
+    public void testBoolean() {
+        test("booleanSnippet");
+        test("opaqueBooleanSnippet");
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static int intSnippet() {
+        return 5 + 3;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = AddNode.class)
+    public static int opaqueIntSnippet() {
+        return 5 + GraalDirectives.opaque(3);
+    }
+
+    @Test
+    public void testInt() {
+        test("intSnippet");
+        test("opaqueIntSnippet");
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static double doubleSnippet() {
+        return 5. + 3.;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = AddNode.class)
+    public static double opaqueDoubleSnippet() {
+        return 5. + GraalDirectives.opaque(3.);
+    }
+
+    @Test
+    public void testDouble() {
+        test("doubleSnippet");
+        test("opaqueDoubleSnippet");
+    }
+
+    private static class Dummy {
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static boolean objectSnippet() {
+        Object obj = new Dummy();
+        return obj == null;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConditionalNode.class)
+    public static boolean opaqueObjectSnippet() {
+        Object obj = new Dummy();
+        return GraalDirectives.opaque(obj) == null;
+    }
+
+    @Test
+    public void testObject() {
+        test("objectSnippet");
+        test("opaqueObjectSnippet");
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) {
+            Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass());
+        }
+        return true;
+    }
+}
--- /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/ProbabilityDirectiveTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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 org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+
+public class ProbabilityDirectiveTest extends GraalCompilerTest {
+
+    public static int branchProbabilitySnippet(int arg) {
+        if (GraalDirectives.injectBranchProbability(0.125, arg > 0)) {
+            GraalDirectives.controlFlowAnchor(); // prevent removal of the if
+            return 1;
+        } else {
+            GraalDirectives.controlFlowAnchor(); // prevent removal of the if
+            return 2;
+        }
+    }
+
+    @Test
+    public void testBranchProbability() {
+        test("branchProbabilitySnippet", 5);
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.class);
+        Assert.assertEquals("IfNode count", 1, ifNodes.count());
+
+        IfNode ifNode = ifNodes.first();
+        AbstractBeginNode trueSuccessor = ifNode.trueSuccessor();
+        Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(trueSuccessor), 0);
+
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,277 @@
+/*
+ * 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;
+
+/**
+ * Directives that influence the compilation of methods by Graal. They don't influence the semantics
+ * of the code, but they are useful for unit testing and benchmarking.
+ */
+public final class GraalDirectives {
+
+    public static final double LIKELY_PROBABILITY = 0.75;
+    public static final double UNLIKELY_PROBABILITY = 1.0 - LIKELY_PROBABILITY;
+
+    public static final double SLOWPATH_PROBABILITY = 0.0001;
+    public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY;
+
+    /**
+     * Directive for the compiler to fall back to the bytecode interpreter at this point.
+     */
+    public static void deoptimize() {
+    }
+
+    /**
+     * Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate
+     * the compiled code and reprofile the method.
+     */
+    public static void deoptimizeAndInvalidate() {
+    }
+
+    /**
+     * Returns a boolean value indicating whether the method is executed in Graal-compiled code.
+     */
+    public static boolean inCompiledCode() {
+        return false;
+    }
+
+    /**
+     * A call to this method will never be duplicated by control flow optimizations in the compiler.
+     */
+    public static void controlFlowAnchor() {
+    }
+
+    /**
+     * Injects a probability for the given condition into the profiling information of a branch
+     * instruction. The probability must be a value between 0.0 and 1.0 (inclusive).
+     *
+     * Example usage (it specifies that the likelihood for a to be greater than b is 90%):
+     *
+     * <code>
+     * if (injectBranchProbability(0.9, a &gt; b)) {
+     *    // ...
+     * }
+     * </code>
+     *
+     * There are predefined constants for commonly used probabilities (see
+     * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY},
+     * {@link #FASTPATH_PROBABILITY} ).
+     *
+     * @param probability the probability value between 0.0 and 1.0 that should be injected
+     */
+    public static boolean injectBranchProbability(double probability, boolean condition) {
+        assert probability >= 0.0 && probability <= 1.0;
+        return condition;
+    }
+
+    /**
+     * Injects an average iteration count of a loop into the probability information of a loop exit
+     * condition. The iteration count specifies how often the condition is checked, i.e. in for and
+     * while loops it is one more than the body iteration count, and in do-while loops it is equal
+     * to the body iteration count. The iteration count must be >= 1.0.
+     *
+     * Example usage (it specifies that the expected iteration count of the loop condition is 500,
+     * so the iteration count of the loop body is 499):
+     *
+     * <code>
+     * for (int i = 0; injectIterationCount(500, i < array.length); i++) {
+     *     // ...
+     * }
+     * </code>
+     *
+     * @param iterations the expected number of iterations that should be injected
+     */
+    public static boolean injectIterationCount(double iterations, boolean condition) {
+        return injectBranchProbability(1. - 1. / iterations, condition);
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(boolean value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(byte value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(short value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(char value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(int value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(long value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(float value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(double value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(Object value) {
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static boolean opaque(boolean value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static byte opaque(byte value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static short opaque(short value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static char opaque(char value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static int opaque(int value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static long opaque(long value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static float opaque(float value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static double opaque(double value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static <T> T opaque(T value) {
+        return value;
+    }
+}
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java	Sat Jan 31 19:03:33 2015 +0100
@@ -41,7 +41,8 @@
     Class<?> value() default ClassSubstitution.class;
 
     /**
-     * Specifies the original class.
+     * Specifies the original class or classes if a single class is being used for multiple
+     * substitutions.
      * <p>
      * This method is provided for cases where the original class is not accessible (according to
      * Java language access control rules).
@@ -49,7 +50,7 @@
      * If the default value is specified for this element, then a non-default value must be given
      * for the {@link #value()} element.
      */
-    String className() default "";
+    String[] className() default {};
 
     /**
      * Determines if the substitutions are for classes that may not be part of the runtime.
--- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java	Sat Jan 31 19:03:33 2015 +0100
@@ -38,7 +38,9 @@
         protected List<Service> computeValue(Class<?> type) {
             Service[] names = getServiceImpls(type);
             if (names == null || names.length == 0) {
-                throw new InternalError(format("No implementations for %s found (ensure %s extends %s)", type.getSimpleName(), type.getSimpleName(), Service.class));
+                throw new InternalError(
+                                format("No implementations for %s found (ensure %s extends %s and that in suite.py the \"annotationProcessors\" attribute for the project enclosing %s includes \"com.oracle.graal.service.processor\")",
+                                                type.getSimpleName(), type.getSimpleName(), Service.class, type.getSimpleName()));
             }
             return Arrays.asList(names);
         }
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Sat Jan 31 19:03:33 2015 +0100
@@ -44,6 +44,7 @@
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 import com.oracle.graal.phases.*;
 
 public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool {
@@ -128,7 +129,6 @@
 
             RegisterConfig registerConfig = null;
             FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
-            frameMapBuilder.requireMapping(lir);
             TargetDescription target = backend.getTarget();
             CallingConvention cc = CodeUtil.getCallingConvention(backend.getProviders().getCodeCache(), CallingConvention.Type.JavaCallee, method, false);
             this.lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, method, null);
@@ -153,22 +153,17 @@
                 try (Scope s = Debug.scope("Allocator")) {
                     if (backend.shouldAllocateRegisters()) {
                         LinearScan.allocate(target, lirGenRes);
-                    } else if (!LocationMarker.Options.UseLocationMarker.getValue()) {
-                        // build frame map for targets that do not allocate registers
-                        lirGenRes.buildFrameMap();
                     }
                 }
-                if (LocationMarker.Options.UseLocationMarker.getValue()) {
-                    try (Scope s1 = Debug.scope("BuildFrameMap")) {
-                        // build frame map
-                        lirGenRes.buildFrameMap();
-                        Debug.dump(lir, "After FrameMap building");
-                    }
-                    try (Scope s1 = Debug.scope("MarkLocations")) {
-                        if (backend.shouldAllocateRegisters()) {
-                            // currently we mark locations only if we do register allocation
-                            LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
-                        }
+                try (Scope s1 = Debug.scope("BuildFrameMap")) {
+                    // build frame map
+                    lirGenRes.buildFrameMap(new SimpleStackSlotAllocator());
+                    Debug.dump(lir, "After FrameMap building");
+                }
+                try (Scope s1 = Debug.scope("MarkLocations")) {
+                    if (backend.shouldAllocateRegisters()) {
+                        // currently we mark locations only if we do register allocation
+                        LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
                     }
                 }
 
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Sat Jan 31 19:03:33 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 
 /**
@@ -50,7 +51,7 @@
     private final GraphBuilderConfiguration graphBuilderConfig;
 
     public CompilationResult generate(ResolvedJavaMethod method, int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
-                    CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts) {
+                    CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts, Replacements replacements) {
         assert method.getCode() != null : "method must contain bytecodes: " + method;
         TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -67,7 +67,7 @@
         StructuredGraph graph = new StructuredGraph(javaMethod);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
-        new GraphBuilderPhase.Instance(getMetaAccess(), conf, OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, conf, OptimisticOptimizations.ALL).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.directives.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
@@ -524,7 +525,7 @@
         try (Scope bds = Debug.scope("CompileBaseline", javaMethod, providers.getCodeCache())) {
             BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess());
             OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
-            return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default, optimisticOpts);
+            return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default, optimisticOpts, getReplacements());
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -720,7 +721,7 @@
         StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner) : graph;
         lastCompiledGraph = graphToCompile;
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graphToCompile.method(), false);
-        Request<CompilationResult> request = new Request<>(graphToCompile, null, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
+        Request<CompilationResult> request = new Request<>(graphToCompile, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
                         OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         return GraalCompiler.compile(request);
     }
@@ -855,7 +856,7 @@
      * @return cond
      */
     protected static boolean branchProbability(double p, boolean cond) {
-        return cond;
+        return GraalDirectives.injectBranchProbability(p, cond);
     }
 
     /**
@@ -867,7 +868,7 @@
      * @return cond
      */
     protected static boolean iterationCount(double i, boolean cond) {
-        return cond;
+        return GraalDirectives.injectIterationCount(i, cond);
     }
 
     /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTestSubstitutions.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTestSubstitutions.java	Sat Jan 31 19:03:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,22 +24,11 @@
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 
 @ClassSubstitution(GraalCompilerTest.class)
 class GraalCompilerTestSubstitutions {
 
     @MethodSubstitution
-    public static boolean branchProbability(double p, boolean cond) {
-        return BranchProbabilityNode.probability(p, cond);
-    }
-
-    @MethodSubstitution
-    public static boolean iterationCount(double i, boolean cond) {
-        return BranchProbabilityNode.probability(1. - 1. / i, cond);
-    }
-
-    @MethodSubstitution
     public static void breakpoint() {
         BreakpointNode.breakpoint();
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -60,7 +60,7 @@
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
         final StructuredGraph graph = parseEager(method);
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        final CompilationResult cr = compileGraph(graph, null, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
+        final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
                         OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
@@ -83,7 +83,7 @@
         assertTrue(graphLineSPs > 0);
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
         PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault());
-        final CompilationResult cr = compileGraph(graph, null, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL,
+        final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL,
                         getProfilingInfo(graph), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Sat Jan 31 19:03:33 2015 +0100
@@ -151,8 +151,8 @@
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
         graph = new StructuredGraph(method);
         try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
-            new GraphBuilderPhase.Instance(getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
             Assumptions assumptions = new Assumptions(false);
+            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
             context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.tutorial;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+
+/**
+ * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at
+ * the examples in IGV (the graph visualization tool), use the options -G:Dump and -G:MethodFilter.
+ * For example, run the first test case using
+ *
+ * <pre>
+ * mx unittest -G:Dump= -G:MethodFilter=String.hashCode GraalTutorial#testStringHashCode
+ * </pre>
+ */
+public class GraalTutorial extends InvokeGraal {
+
+    /*
+     * A simple Graal compilation example: Compile the method String.hashCode()
+     */
+
+    @Test
+    public void testStringHashCode() throws InvalidInstalledCodeException {
+        InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode"));
+
+        int result = (int) installedCode.executeVarargs("Hello World");
+        Assert.assertEquals(-862545276, result);
+    }
+
+    /*
+     * Tutorial example for speculative optimizations.
+     */
+
+    int f1;
+    int f2;
+
+    public void speculativeOptimization(boolean flag) {
+        f1 = 41;
+        if (flag) {
+            f2 = 42;
+            return;
+        }
+        f2 = 43;
+    }
+
+    @Test
+    public void testSpeculativeOptimization() throws InvalidInstalledCodeException {
+        /*
+         * Collect profiling information by running the method in the interpreter.
+         */
+        for (int i = 0; i < 10000; i++) {
+            speculativeOptimization(false);
+        }
+
+        /*
+         * Warmup to collect profiling information is done, now we compile the method. Since the
+         * value of "flag" was always false during the warmup, the compiled code speculates that the
+         * value remains false.
+         */
+
+        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
+        f1 = 0;
+        f2 = 0;
+        compiledMethod.executeVarargs(this, true);
+        Assert.assertEquals(41, f1);
+        Assert.assertEquals(42, f2);
+
+        /*
+         * We executed the compiled method with a "flag" value that triggered deoptimization (since
+         * the warmup always used the different "flag" value). The interpreter updated the profiling
+         * information, so the second compilation does not perform the speculative optimization.
+         */
+
+        compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
+        f1 = 0;
+        f2 = 0;
+        compiledMethod.executeVarargs(this, false);
+        Assert.assertEquals(41, f1);
+        Assert.assertEquals(43, f2);
+    }
+
+    /*
+     * Tutorial example for snippets and lowering.
+     */
+
+    static class A {
+    }
+
+    static class B extends A {
+    }
+
+    public static int instanceOfUsage(Object obj) {
+        if (obj instanceof A) {
+            return 42;
+        } else {
+            return 0;
+        }
+    }
+
+    @Test
+    public void testInstanceOfUsage() throws InvalidInstalledCodeException {
+        A a = new A();
+
+        /* Allocate an (unsued) instance of B so that the class B gets loaded. */
+        @SuppressWarnings("unused")
+        B b = new B();
+
+        for (int i = 0; i < 10000; i++) {
+            instanceOfUsage(a);
+        }
+
+        /* Warmup to collect profiling information is done, now compile the method. */
+
+        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage"));
+
+        int result = (int) compiledMethod.executeVarargs(a);
+        Assert.assertEquals(42, result);
+    }
+
+    /*
+     * Tutorial example for intrinsic methods.
+     */
+
+    public static double intrinsicUsage(double val) {
+        return Math.sin(val);
+    }
+
+    @Test
+    public void testIntrinsicUsage() throws InvalidInstalledCodeException {
+        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage"));
+
+        double result = (double) compiledMethod.executeVarargs(42d);
+        Assert.assertEquals(Math.sin(42), result, 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.tutorial;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.runtime.*;
+
+/**
+ * Sample code that shows how to invoke Graal from an application.
+ */
+public class InvokeGraal {
+
+    protected final Backend backend;
+    protected final Providers providers;
+    protected final MetaAccessProvider metaAccess;
+    protected final CodeCacheProvider codeCache;
+    protected final TargetDescription target;
+
+    public InvokeGraal() {
+        /* Ask the hosting Java VM for the entry point object to the Graal API. */
+        RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class);
+
+        /* The default backend (architecture, VM configuration) that the hosting VM is running on. */
+        backend = runtimeProvider.getHostBackend();
+        /* Access to all of the Graal API providers, as implemented by the hosting VM. */
+        providers = backend.getProviders();
+        /* Some frequently used providers and configuration objects. */
+        metaAccess = providers.getMetaAccess();
+        codeCache = providers.getCodeCache();
+        target = codeCache.getTarget();
+    }
+
+    private static AtomicInteger compilationId = new AtomicInteger();
+
+    /**
+     * The simplest way to compile a method, using the default behavior for everything.
+     */
+    protected InstalledCode compileAndInstallMethod(ResolvedJavaMethod method) {
+        /* Ensure every compilation gets a unique number, visible in IGV. */
+        try (Scope s = Debug.scope("compileAndInstallMethod", new DebugDumpScope(String.valueOf(compilationId.incrementAndGet()), true))) {
+
+            /*
+             * The graph that is compiled. We leave it empty (no nodes added yet). This means that
+             * it will be filled according to the graphBuilderSuite defined below.
+             */
+            StructuredGraph graph = new StructuredGraph(method);
+
+            /*
+             * The phases used to build the graph. Usually this is just the GraphBuilderPhase. If
+             * the graph already contains nodes, it is ignored.
+             */
+            PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite();
+
+            /*
+             * The optimization phases that are applied to the graph. This is the main configuration
+             * point for Graal. Add or remove phases to customize your compilation.
+             */
+            Suites suites = backend.getSuites().createSuites();
+
+            /*
+             * The calling convention for the machine code. You should have a very good reason
+             * before you switch to a different calling convention than the one that the VM provides
+             * by default.
+             */
+            CallingConvention callingConvention = CodeUtil.getCallingConvention(codeCache, Type.JavaCallee, method, false);
+
+            /*
+             * We want Graal to perform all speculative optimisitic optimizations, using the
+             * profiling information that comes with the method (collected by the interpreter) for
+             * speculation.
+             */
+            OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
+            ProfilingInfo profilingInfo = method.getProfilingInfo();
+
+            /* The default class and configuration for compilation results. */
+            CompilationResult compilationResult = new CompilationResult();
+            CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
+
+            /* Advanced configuration objects that are not mandatory. */
+            Map<ResolvedJavaMethod, StructuredGraph> cache = null;
+            SpeculationLog speculationLog = null;
+
+            /* Invoke the whole Graal compilation pipeline. */
+            GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites,
+                            compilationResult, factory);
+
+            /*
+             * Install the compilation result into the VM, i.e., copy the byte[] array that contains
+             * the machine code into an actual executable memory location.
+             */
+            InstalledCode installedCode = codeCache.addMethod(method, compilationResult, null, null);
+
+            return installedCode;
+        } catch (Throwable ex) {
+            throw Debug.handle(ex);
+        }
+    }
+
+    /**
+     * Look up a method using Java reflection and convert it to the Graal API method object.
+     */
+    protected ResolvedJavaMethod findMethod(Class<?> declaringClass, String name) {
+        Method reflectionMethod = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (m.getName().equals(name)) {
+                assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName();
+                reflectionMethod = m;
+            }
+        }
+        assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName();
+        return metaAccess.lookupJavaMethod(reflectionMethod);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.tutorial;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+/**
+ * A simple context-insensitive static analysis based on the Graal API. It is intended for
+ * educational purposes, not for use in production. Only a limited set of Java functionality is
+ * supported to keep the code minimal.
+ * <p>
+ * The analysis builds a directed graph of {@link TypeFlow type flows}. If a type is added to type
+ * flow, it is propagated to all {@link TypeFlow#uses uses} of the type flow. Types are propagated
+ * using a {@link #worklist} of changed type flows until a fixpoint is reached, i.e., until no more
+ * types need to be added to any type state.
+ * <p>
+ * The type flows are constructed from a high-level Graal graph by the {@link TypeFlowBuilder}. All
+ * nodes that operate on {@link Kind#Object object} values are converted to the appropriate type
+ * flows. The analysis is context insensitive: every Java field has {@link Results#lookupField one
+ * list} of types assigned to the field; every Java method has {@link Results#lookupMethod one
+ * state} for each {@link MethodState#formalParameters parameter} as well as the
+ * {@link MethodState#formalReturn return value}.
+ */
+public class StaticAnalysis {
+    /** Access to type, method, and fields using the Graal API. */
+    private final MetaAccessProvider metaAccess;
+    /** Access to platform dependent stamps. */
+    private final StampProvider stampProvider;
+    /** The results of the static analysis. */
+    private final Results results;
+    /** Worklist for fixpoint iteration. */
+    private final Deque<WorklistEntry> worklist;
+
+    public StaticAnalysis(MetaAccessProvider metaAccess, StampProvider stampProvider) {
+        this.metaAccess = metaAccess;
+        this.stampProvider = stampProvider;
+        this.results = new Results();
+        this.worklist = new ArrayDeque<>();
+    }
+
+    /**
+     * 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.
+     */
+    public void addMethod(ResolvedJavaMethod method) {
+        if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) {
+            error("Entry point method is not static or has parameters: " + method.format("%H.%n(%p)"));
+        }
+        addToWorklist(results.lookupMethod(method));
+    }
+
+    /**
+     * Performs the fixed-point analysis that finds all methods transitively reachable from the
+     * {@link #addMethod root methods}.
+     */
+    public void finish() {
+        while (!worklist.isEmpty()) {
+            worklist.removeFirst().process();
+        }
+    }
+
+    /**
+     * Returns the static analysis results computed by {@link StaticAnalysis#finish}.
+     */
+    public Results getResults() {
+        return results;
+    }
+
+    protected void addToWorklist(WorklistEntry task) {
+        worklist.addLast(task);
+    }
+
+    protected static RuntimeException error(String msg) {
+        throw GraalInternalError.shouldNotReachHere(msg);
+    }
+
+    /**
+     * Base class for all work items that can be {@link #addToWorklist added to the worklist}.
+     */
+    abstract class WorklistEntry {
+        protected abstract void process();
+    }
+
+    /**
+     * The results computed by the static analysis.
+     */
+    public class Results {
+        private final TypeFlow allInstantiatedTypes;
+        private final Map<ResolvedJavaField, TypeFlow> fields;
+        private final Map<ResolvedJavaMethod, MethodState> methods;
+
+        protected Results() {
+            allInstantiatedTypes = new TypeFlow();
+            fields = new HashMap<>();
+            methods = new HashMap<>();
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that are found to be instantiated, i.e., all types
+         * allocated by the reachable instance and array allocation bytecodes.
+         */
+        public TypeFlow getAllInstantiatedTypes() {
+            return allInstantiatedTypes;
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that the given field can have, i.e., all types
+         * assigned by the reachable field store bytecodes.
+         */
+        public TypeFlow lookupField(ResolvedJavaField field) {
+            TypeFlow result = fields.get(field);
+            if (result == null) {
+                result = new TypeFlow();
+                fields.put(field, result);
+            }
+            return result;
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that {@link MethodState#formalParameters
+         * parameters} and {@link MethodState#formalReturn return value} of the given method can
+         * have.
+         */
+        public MethodState lookupMethod(ResolvedJavaMethod method) {
+            MethodState result = methods.get(method);
+            if (result == null) {
+                result = new MethodState(method);
+                methods.put(method, result);
+            }
+            return result;
+        }
+    }
+
+    /**
+     * The {@link TypeFlow#getTypes() types} of the parameters and return value of a method. Also
+     * serves as the worklist element to parse the bytecodes of the method.
+     */
+    public class MethodState extends WorklistEntry {
+        private final ResolvedJavaMethod method;
+        private final TypeFlow[] formalParameters;
+        private final TypeFlow formalReturn;
+        private boolean processed;
+
+        protected MethodState(ResolvedJavaMethod method) {
+            this.method = method;
+
+            formalParameters = new TypeFlow[method.getSignature().getParameterCount(!method.isStatic())];
+            for (int i = 0; i < formalParameters.length; i++) {
+                formalParameters[i] = new TypeFlow();
+            }
+            formalReturn = new TypeFlow();
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that the parameters of this method can have.
+         */
+        public TypeFlow[] getFormalParameters() {
+            return formalParameters;
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that the return value of this method can have.
+         */
+        public TypeFlow getFormalReturn() {
+            return formalReturn;
+        }
+
+        @Override
+        protected void process() {
+            if (!processed) {
+                /* We want to process a method only once. */
+                processed = true;
+
+                /*
+                 * Build the Graal graph for the method using the bytecode parser provided by Graal.
+                 */
+
+                StructuredGraph graph = new StructuredGraph(method);
+                /*
+                 * Support for graph dumping, IGV uses this information to show the method name of a
+                 * graph.
+                 */
+                try (Scope scope = Debug.scope("graph building", graph)) {
+                    /*
+                     * We want all types to be resolved by the graph builder, i.e., we want classes
+                     * referenced by the bytecodes to be loaded and initialized. Since we do not run
+                     * 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);
+                    /*
+                     * 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
+                     * handle the Graal nodes for throwing and handling exceptions.
+                     */
+                    graphBuilderConfig = graphBuilderConfig.withOmitAllExceptionEdges(true);
+                    /*
+                     * We do not want Graal to perform any speculative optimistic optimizations,
+                     * i.e., we do not want to use profiling information. Since we do not run the
+                     * code before static analysis, the profiling information is empty and therefore
+                     * wrong.
+                     */
+                    OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
+                    Assumptions assumptions = new Assumptions(false);
+
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
+                    graphBuilder.apply(graph);
+                } catch (Throwable ex) {
+                    Debug.handle(ex);
+                }
+
+                /*
+                 * Build the type flow graph from the Graal graph, i.e., process all nodes that are
+                 * deal with objects.
+                 */
+
+                TypeFlowBuilder typeFlowBuilder = new TypeFlowBuilder(graph);
+                typeFlowBuilder.apply();
+            }
+        }
+    }
+
+    /**
+     * The active element during static analysis: types are added until a fixed point is reached.
+     * When a new type is added, it is propagated to all usages by putting this element on the
+     * {@link StaticAnalysis#addToWorklist worklist}.
+     */
+    public class TypeFlow extends WorklistEntry {
+        private final Set<ResolvedJavaType> types;
+        private final Set<TypeFlow> uses;
+
+        protected TypeFlow() {
+            types = new HashSet<>();
+            uses = new HashSet<>();
+        }
+
+        /** Returns the types of this element. */
+        public Set<ResolvedJavaType> getTypes() {
+            return types;
+        }
+
+        /**
+         * Adds new types to this element. If that changes the state of this element, it is added to
+         * the {@link StaticAnalysis#addToWorklist worklist} in order to propagate the added types
+         * to all usages.
+         */
+        protected void addTypes(Set<ResolvedJavaType> newTypes) {
+            if (types.addAll(newTypes)) {
+                addToWorklist(this);
+            }
+        }
+
+        /**
+         * Adds a new use to this element. All types of this element are propagated to the new
+         * usage.
+         */
+        protected void addUse(TypeFlow use) {
+            if (uses.add(use)) {
+                use.addTypes(types);
+            }
+        }
+
+        /**
+         * Processing of the worklist element: propagate the types to all usages. That in turn can
+         * add the usages to the worklist (if the types of the usage are changed).
+         */
+        @Override
+        protected void process() {
+            for (TypeFlow use : uses) {
+                use.addTypes(types);
+            }
+        }
+    }
+
+    /**
+     * 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
+     * parameters of the callee, and linking the return value of the callee with the return value
+     * state of the invocation.
+     *
+     * Statically bindable methods calls ({@link InvokeKind#Static static} and
+     * {@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;
+        private final TypeFlow actualReturn;
+        private final Set<ResolvedJavaMethod> callees;
+
+        protected InvokeTypeFlow(MethodCallTargetNode callTarget, TypeFlow[] actualParameterFlows, TypeFlow actualReturnFlow) {
+            this.callTarget = callTarget;
+            this.actualParameters = actualParameterFlows;
+            this.actualReturn = actualReturnFlow;
+            this.callees = new HashSet<>();
+        }
+
+        private void linkCallee(ResolvedJavaMethod callee) {
+            if (callees.add(callee)) {
+                /* We have added a new callee. */
+
+                /*
+                 * Connect the actual parameters of the invocation with the formal parameters of the
+                 * callee.
+                 */
+                MethodState calleeState = results.lookupMethod(callee);
+                for (int i = 0; i < actualParameters.length; i++) {
+                    if (actualParameters[i] != null) {
+                        actualParameters[i].addUse(calleeState.formalParameters[i]);
+                    }
+                }
+
+                /*
+                 * Connect the formal return value of the callee with the actual return value of the
+                 * invocation.
+                 */
+                if (actualReturn != null) {
+                    calleeState.formalReturn.addUse(actualReturn);
+                }
+                addToWorklist(calleeState);
+            }
+        }
+
+        @Override
+        protected void process() {
+            if (callTarget.invokeKind().isDirect()) {
+                /* Static and special calls: link the statically known callee method. */
+                linkCallee(callTarget.targetMethod());
+            } else {
+                /* Virtual and interface call: Iterate all receiver types. */
+                for (ResolvedJavaType type : getTypes()) {
+                    /*
+                     * Resolve the method call for one exact receiver type. The method linking
+                     * semantics of Java are complicated, but fortunatley we can use the linker of
+                     * the hosting Java VM. The Graal API exposes this functionality.
+                     */
+                    ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), callTarget.invoke().getContextType());
+
+                    /*
+                     * Since the static analysis is conservative, the list of receiver types can
+                     * contain types that actually do not provide the method to be called. Ignore
+                     * these.
+                     */
+                    if (method != null && !method.isAbstract()) {
+                        linkCallee(method);
+                    }
+                }
+            }
+            super.process();
+        }
+    }
+
+    /**
+     * Converts the Graal nodes of a method to a type flow graph. The main part of the algorithm is
+     * a reverse-postorder iteration of the Graal nodes, which is provided by the base class
+     * {@link StatelessPostOrderNodeIterator}.
+     */
+    class TypeFlowBuilder extends StatelessPostOrderNodeIterator {
+        private final StructuredGraph graph;
+        private final MethodState methodState;
+        /**
+         * Mapping from Graal nodes to type flows. This uses an efficient Graal-provided
+         * {@link NodeMap collection class}.
+         */
+        private final NodeMap<TypeFlow> typeFlows;
+
+        protected TypeFlowBuilder(StructuredGraph graph) {
+            super(graph.start());
+
+            this.graph = graph;
+            this.methodState = results.lookupMethod(graph.method());
+            this.typeFlows = new NodeMap<>(graph);
+        }
+
+        /**
+         * Register the type flow node for a Graal node.
+         */
+        private void registerFlow(ValueNode node, TypeFlow flow) {
+            /*
+             * We ignore intermediate nodes used by Graal that, e.g., add more type information or
+             * encapsulate values flowing out of loops.
+             */
+            ValueNode unproxiedNode = GraphUtil.unproxify(node);
+
+            assert typeFlows.get(unproxiedNode) == null : "overwriting existing value";
+            typeFlows.set(unproxiedNode, flow);
+        }
+
+        /**
+         * Lookup the type flow node for a Graal node.
+         */
+        private TypeFlow lookupFlow(ValueNode node) {
+            ValueNode unproxiedNode = GraphUtil.unproxify(node);
+            TypeFlow result = typeFlows.get(unproxiedNode);
+            if (result == null) {
+                /*
+                 * This is only the prototype of a static analysis, the handling of many Graal nodes
+                 * (such as array accesses) is not implemented.
+                 */
+                throw error("Node is not supported yet by static analysis: " + node.getClass().getName());
+            }
+            return result;
+        }
+
+        private boolean isObject(ValueNode node) {
+            return node.getKind() == Kind.Object;
+        }
+
+        @Override
+        public void apply() {
+            /*
+             * Before the reverse-postorder iteration of fixed nodes, we handle some classes of
+             * floating nodes.
+             */
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ParameterNode) {
+                    /*
+                     * Incoming method parameter already have a type flow created by the
+                     * MethodState.
+                     */
+                    ParameterNode node = (ParameterNode) n;
+                    if (isObject(node)) {
+                        registerFlow(node, methodState.formalParameters[(node.index())]);
+                    }
+                } else if (n instanceof ValuePhiNode) {
+                    /*
+                     * Phi functions for loops are cyclic. We create the type flow here (before
+                     * processing any loop nodes), but link the phi values only later (after
+                     * processing of all loop nodes.
+                     */
+                    ValuePhiNode node = (ValuePhiNode) n;
+                    if (isObject(node)) {
+                        registerFlow(node, new TypeFlow());
+                    }
+                } else if (n instanceof ConstantNode) {
+                    /* Constants have a known type. */
+                    ConstantNode node = (ConstantNode) n;
+                    JavaConstant constant = node.asJavaConstant();
+                    if (constant.isNull()) {
+                        registerFlow(node, new TypeFlow());
+                    }
+                }
+            }
+
+            super.apply();
+
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ValuePhiNode) {
+                    /*
+                     * Post-processing of phi functions. Now the type flow for all input values has
+                     * been created, so we can link the type flows together.
+                     */
+                    ValuePhiNode node = (ValuePhiNode) n;
+                    if (isObject(node)) {
+                        TypeFlow phiFlow = lookupFlow(node);
+                        for (ValueNode value : node.values()) {
+                            lookupFlow(value).addUse(phiFlow);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void allocation(ValueNode node, ResolvedJavaType type) {
+            /*
+             * The type flow of allocation nodes is one exact type. This is the source of the
+             * fixpoint iteration, the types are propagated downwards from these sources.
+             */
+            TypeFlow flow = new TypeFlow();
+            flow.addTypes(Collections.singleton(type));
+            registerFlow(node, flow);
+            flow.addUse(results.getAllInstantiatedTypes());
+        }
+
+        @Override
+        protected void node(FixedNode n) {
+            if (n instanceof NewInstanceNode) {
+                NewInstanceNode node = (NewInstanceNode) n;
+                allocation(node, node.instanceClass());
+            } else if (n instanceof NewArrayNode) {
+                NewArrayNode node = (NewArrayNode) n;
+                allocation(node, node.elementType().getArrayClass());
+
+            } else if (n instanceof LoadFieldNode) {
+                /*
+                 * The type flow of a field load is the type flow of the field itself. It
+                 * accumulates all types ever stored to the field.
+                 */
+                LoadFieldNode node = (LoadFieldNode) n;
+                if (isObject(node)) {
+                    registerFlow(node, results.lookupField(node.field()));
+                }
+            } else if (n instanceof StoreFieldNode) {
+                /*
+                 * Connect the type flow of the stored value with the type flow of the field.
+                 */
+                StoreFieldNode node = (StoreFieldNode) n;
+                if (isObject(node.value())) {
+                    TypeFlow fieldFlow = results.lookupField(node.field());
+                    lookupFlow(node.value()).addUse(fieldFlow);
+                }
+
+            } else if (n instanceof ReturnNode) {
+                /*
+                 * Connect the type flow of the returned value with the formal return type flow of
+                 * the MethodState.
+                 */
+                ReturnNode node = (ReturnNode) n;
+                if (node.result() != null && isObject(node.result())) {
+                    lookupFlow(node.result()).addUse(methodState.formalReturn);
+                }
+
+            } else if (n instanceof Invoke) {
+                /*
+                 * Create the InvokeTypeFlow, which performs all the linking of actual and formal
+                 * parameter values with all identified callees.
+                 */
+                Invoke invoke = (Invoke) n;
+                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+
+                TypeFlow[] actualParameters = new TypeFlow[callTarget.arguments().size()];
+                for (int i = 0; i < actualParameters.length; i++) {
+                    ValueNode actualParam = callTarget.arguments().get(i);
+                    if (isObject(actualParam)) {
+                        actualParameters[i] = lookupFlow(actualParam);
+                    }
+                }
+                TypeFlow actualReturn = null;
+                if (isObject(invoke.asNode())) {
+                    actualReturn = new TypeFlow();
+                    registerFlow(invoke.asNode(), actualReturn);
+                }
+
+                InvokeTypeFlow invokeFlow = new InvokeTypeFlow(callTarget, actualParameters, actualReturn);
+
+                if (callTarget.invokeKind().isIndirect()) {
+                    /*
+                     * For virtual and interface calls, new receiver types can lead to new callees.
+                     * Connect the type flow of the receiver with the invocation flow.
+                     */
+                    lookupFlow(callTarget.arguments().get(0)).addUse(invokeFlow);
+                }
+                /*
+                 * Ensure the invocation is on the worklist at least once, even if it is a static
+                 * call with not parameters that does not involve any type flows.
+                 */
+                addToWorklist(invokeFlow);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysisTests.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.tutorial;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.test.tutorial.StaticAnalysis.MethodState;
+import com.oracle.graal.compiler.test.tutorial.StaticAnalysis.TypeFlow;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.runtime.*;
+
+public class StaticAnalysisTests {
+
+    static class A {
+        Object foo(Object arg) {
+            return arg;
+        }
+    }
+
+    static class B extends A {
+        @Override
+        Object foo(Object arg) {
+            if (arg instanceof Data) {
+                return ((Data) arg).f;
+            } else {
+                return super.foo(arg);
+            }
+        }
+    }
+
+    static class Data {
+        Object f;
+    }
+
+    private final MetaAccessProvider metaAccess;
+    private final StampProvider stampProvider;
+
+    public StaticAnalysisTests() {
+        Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        Providers providers = backend.getProviders();
+        this.metaAccess = providers.getMetaAccess();
+        this.stampProvider = providers.getStampProvider();
+    }
+
+    static void test01Entry() {
+        A a = new A();
+        a.foo(null);
+    }
+
+    @Test
+    public void test01() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class));
+        assertEquals(f(sa, Data.class, "f"));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1]);
+        assertEquals(m(sa, A.class, "foo").getFormalReturn());
+    }
+
+    static void test02Entry() {
+        A a = new A();
+        a.foo(new Data());
+
+        B b = new B();
+        b.foo(null);
+    }
+
+    @Test
+    public void test02() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class));
+        assertEquals(f(sa, Data.class, "f"));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
+        assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]);
+        assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class));
+    }
+
+    static void test03Entry() {
+        Data data = new Data();
+        data.f = new Integer(42);
+
+        A a = new A();
+        a.foo(new Data());
+
+        B b = new B();
+        b.foo(null);
+    }
+
+    @Test
+    public void test03() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class), t(Integer.class));
+        assertEquals(f(sa, Data.class, "f"), t(Integer.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
+        assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]);
+        assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class), t(Integer.class));
+    }
+
+    static void test04Entry() {
+        Data data = null;
+        for (int i = 0; i < 2; i++) {
+            if (i == 0) {
+                data = new Data();
+            } else if (i == 1) {
+                data.f = new Integer(42);
+            }
+        }
+
+        A a = new A();
+        a.foo(data);
+    }
+
+    @Test
+    public void test04() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(Data.class), t(Integer.class));
+        assertEquals(f(sa, Data.class, "f"), t(Integer.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
+        assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
+    }
+
+    private MethodState m(StaticAnalysis sa, Class<?> declaringClass, String name) {
+        return sa.getResults().lookupMethod(findMethod(declaringClass, name));
+    }
+
+    private TypeFlow f(StaticAnalysis sa, Class<?> declaringClass, String name) {
+        return sa.getResults().lookupField(findField(declaringClass, name));
+    }
+
+    private static void assertEquals(TypeFlow actual, Object... expected) {
+        Collection<?> actualTypes = actual.getTypes();
+        if (actualTypes.size() != expected.length || !actualTypes.containsAll(Arrays.asList(expected))) {
+            Assert.fail(actualTypes + " != " + Arrays.asList(expected));
+        }
+    }
+
+    private ResolvedJavaType t(Class<?> clazz) {
+        return metaAccess.lookupJavaType(clazz);
+    }
+
+    private ResolvedJavaMethod findMethod(Class<?> declaringClass, String name) {
+        Method reflectionMethod = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (m.getName().equals(name)) {
+                assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName();
+                reflectionMethod = m;
+            }
+        }
+        assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName();
+        return metaAccess.lookupJavaMethod(reflectionMethod);
+    }
+
+    private ResolvedJavaField findField(Class<?> declaringClass, String name) {
+        Field reflectionField;
+        try {
+            reflectionField = declaringClass.getDeclaredField(name);
+        } catch (NoSuchFieldException | SecurityException ex) {
+            throw new AssertionError(ex);
+        }
+        return metaAccess.lookupJavaField(reflectionField);
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sat Jan 31 19:03:33 2015 +0100
@@ -46,6 +46,7 @@
 import com.oracle.graal.lir.constopt.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
@@ -131,7 +132,6 @@
      */
     public static class Request<T extends CompilationResult> {
         public final StructuredGraph graph;
-        public final Object stub;
         public final CallingConvention cc;
         public final ResolvedJavaMethod installedCodeOwner;
         public final Providers providers;
@@ -151,7 +151,6 @@
          * @param cc the calling convention for calls to the code compiled for {@code graph}
          * @param installedCodeOwner the method the compiled code will be associated with once
          *            installed. This argument can be null.
-         * @param stub
          * @param providers
          * @param backend
          * @param target
@@ -164,11 +163,10 @@
          * @param compilationResult
          * @param factory
          */
-        public Request(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target,
+        public Request(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target,
                         Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo,
                         SpeculationLog speculationLog, Suites suites, T compilationResult, CompilationResultBuilderFactory factory) {
             this.graph = graph;
-            this.stub = stub;
             this.cc = cc;
             this.installedCodeOwner = installedCodeOwner;
             this.providers = providers;
@@ -203,11 +201,11 @@
      *            installed. This argument can be null.
      * @return the result of the compilation
      */
-    public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
+    public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
                     TargetDescription target, Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
                     ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, T compilationResult, CompilationResultBuilderFactory factory) {
-        return compile(new Request<>(graph, stub, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites,
-                        compilationResult, factory));
+        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, compilationResult,
+                        factory));
     }
 
     /**
@@ -220,7 +218,7 @@
         try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) {
             Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
             SchedulePhase schedule = emitFrontEnd(r.providers, r.target, r.graph, assumptions, r.cache, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.speculationLog, r.suites);
-            emitBackEnd(r.graph, r.stub, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null);
+            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -323,7 +321,6 @@
         }
         try (Scope ds = Debug.scope("BackEnd", lir)) {
             FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
-            frameMapBuilder.requireMapping(lir);
             LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, graph.method(), stub);
             LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
             NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
@@ -351,25 +348,26 @@
             try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
                 if (backend.shouldAllocateRegisters()) {
                     LinearScan.allocate(target, lirGenRes);
-                } else if (!LocationMarker.Options.UseLocationMarker.getValue()) {
-                    // build frame map for targets that do not allocate registers
-                    lirGenRes.buildFrameMap();
                 }
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
 
-            if (LocationMarker.Options.UseLocationMarker.getValue()) {
-                try (Scope s1 = Debug.scope("BuildFrameMap")) {
-                    // build frame map
-                    lirGenRes.buildFrameMap();
-                    Debug.dump(lir, "After FrameMap building");
+            try (Scope s1 = Debug.scope("BuildFrameMap")) {
+                // build frame map
+                final StackSlotAllocator allocator;
+                if (LSStackSlotAllocator.Options.EnableLSStackSlotAllocation.getValue()) {
+                    allocator = new LSStackSlotAllocator();
+                } else {
+                    allocator = new SimpleStackSlotAllocator();
                 }
-                try (Scope s1 = Debug.scope("MarkLocations")) {
-                    if (backend.shouldAllocateRegisters()) {
-                        // currently we mark locations only if we do register allocation
-                        LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
-                    }
+                lirGenRes.buildFrameMap(allocator);
+                Debug.dump(lir, "After FrameMap building");
+            }
+            try (Scope s1 = Debug.scope("MarkLocations")) {
+                if (backend.shouldAllocateRegisters()) {
+                    // currently we mark locations only if we do register allocation
+                    LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
                 }
             }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Sat Jan 31 19:03:33 2015 +0100
@@ -1640,67 +1640,6 @@
         return new IntervalWalker(this, oopIntervals, nonOopIntervals);
     }
 
-    /**
-     * Visits all intervals for a frame state. The frame state use this information to build the OOP
-     * maps.
-     */
-    private void markFrameLocations(IntervalWalker iw, LIRInstruction op, LIRFrameState info, FrameMap frameMap) {
-        Debug.log("creating oop map at opId %d", op.id());
-
-        // walk before the current operation . intervals that start at
-        // the operation (i.e. output operands of the operation) are not
-        // included in the oop map
-        iw.walkBefore(op.id());
-
-        // TODO(je) we could pass this as parameter
-        AbstractBlock<?> block = blockForId(op.id());
-
-        // Iterate through active intervals
-        for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) {
-            Value operand = interval.operand;
-
-            assert interval.currentFrom() <= op.id() && op.id() <= interval.currentTo() : "interval should not be active otherwise";
-            assert isVariable(interval.operand) : "fixed interval found";
-
-            // Check if this range covers the instruction. Intervals that
-            // start or end at the current operation are not included in the
-            // oop map, except in the case of patching moves. For patching
-            // moves, any intervals which end at this instruction are included
-            // in the oop map since we may safepoint while doing the patch
-            // before we've consumed the inputs.
-            if (op.id() < interval.currentTo() && !isIllegal(interval.location())) {
-                // caller-save registers must not be included into oop-maps at calls
-                assert !op.destroysCallerSavedRegisters() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
-
-                info.markLocation(interval.location(), frameMap);
-
-                // Spill optimization: when the stack value is guaranteed to be always correct,
-                // then it must be added to the oop map even if the interval is currently in a
-                // register
-                int spillPos = interval.spillDefinitionPos();
-                if (interval.spillState() != SpillState.SpillInDominator) {
-                    if (interval.alwaysInMemory() && op.id() > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) {
-                        assert interval.spillDefinitionPos() > 0 : "position not set correctly";
-                        assert spillPos > 0 : "position not set correctly";
-                        assert interval.spillSlot() != null : "no spill slot assigned";
-                        assert !isRegister(interval.operand) : "interval is on stack :  so stack slot is registered twice";
-                        info.markLocation(interval.spillSlot(), frameMap);
-                    }
-                } else {
-                    AbstractBlock<?> spillBlock = blockForId(spillPos);
-                    if (interval.alwaysInMemory() && !interval.location().equals(interval.spillSlot())) {
-                        if ((spillBlock.equals(block) && op.id() > spillPos) || dominates(spillBlock, block)) {
-                            assert spillPos > 0 : "position not set correctly";
-                            assert interval.spillSlot() != null : "no spill slot assigned";
-                            assert !isRegister(interval.operand) : "interval is on stack :  so stack slot is registered twice";
-                            info.markLocation(interval.spillSlot(), frameMap);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     private boolean isCallerSave(Value operand) {
         return attributes(asRegister(operand)).isCallerSave();
     }
@@ -1744,20 +1683,11 @@
         return result;
     }
 
-    private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
-        if (!LocationMarker.Options.UseLocationMarker.getValue()) {
-            FrameMap frameMap = res.getFrameMap();
-            info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters);
-            markFrameLocations(iw, op, info, frameMap);
-        }
-
+    private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
         info.forEachState(op, this::debugInfoProcedure);
-        if (!LocationMarker.Options.UseLocationMarker.getValue()) {
-            info.finish(op, res.getFrameMap());
-        }
     }
 
-    private void assignLocations(List<LIRInstruction> instructions, final IntervalWalker iw) {
+    private void assignLocations(List<LIRInstruction> instructions) {
         int numInst = instructions.size();
         boolean hasDead = false;
 
@@ -1792,7 +1722,7 @@
             op.forEachOutput(assignProc);
 
             // compute reference map and debug information
-            op.forEachState((inst, state) -> computeDebugInfo(iw, inst, state));
+            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
 
             // remove useless moves
             if (move != null) {
@@ -1810,41 +1740,15 @@
     }
 
     private void assignLocations() {
-        IntervalWalker iw = initIntervalWalker(IS_STACK_INTERVAL);
         try (Indent indent = Debug.logAndIndent("assign locations")) {
             for (AbstractBlock<?> block : sortedBlocks) {
                 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
-                    assignLocations(ir.getLIRforBlock(block), iw);
+                    assignLocations(ir.getLIRforBlock(block));
                 }
             }
         }
     }
 
-    private class Mapper implements FrameMappable {
-
-        public void map(FrameMappingTool tool) {
-            try (Scope scope = Debug.scope("StackSlotMappingLSRA")) {
-                for (Interval current : intervals) {
-                    if (current != null) {
-                        if (isVirtualStackSlot(current.location())) {
-                            VirtualStackSlot value = asVirtualStackSlot(current.location());
-                            StackSlot stackSlot = tool.getStackSlot(value);
-                            Debug.log("map %s -> %s", value, stackSlot);
-                            current.assignLocation(stackSlot);
-                        }
-                        if (current.isSplitParent() && current.spillSlot() != null && isVirtualStackSlot(current.spillSlot())) {
-                            VirtualStackSlot value = asVirtualStackSlot(current.spillSlot());
-                            StackSlot stackSlot = tool.getStackSlot(value);
-                            Debug.log("map %s -> %s", value, stackSlot);
-                            current.setSpillSlot(stackSlot);
-                        }
-                    }
-                }
-            }
-        }
-
-    }
-
     public static void allocate(TargetDescription target, LIRGenerationResult res) {
         new LinearScan(target, res).allocate();
     }
@@ -1892,16 +1796,6 @@
                 printIntervals("After register allocation");
                 printLir("After register allocation", true);
 
-                // register interval mapper
-                frameMapBuilder.requireMapping(new Mapper());
-
-                if (!LocationMarker.Options.UseLocationMarker.getValue()) {
-                    // build frame map
-                    res.buildFrameMap();
-                }
-
-                printLir("After FrameMap building", true);
-
                 sortIntervalsAfterAllocation();
 
                 if (DetailedAsserts.getValue()) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Sat Jan 31 19:03:33 2015 +0100
@@ -55,7 +55,11 @@
     }
 
     public Set<Node> keySet() {
-        throw new UnsupportedOperationException("Cannot get key set from this map");
+        HashSet<Node> entries = new HashSet<>();
+        for (Map.Entry<Node, Node> entry : entries()) {
+            entries.add(entry.getKey());
+        }
+        return entries;
     }
 
     public Collection<Node> values() {
@@ -69,7 +73,11 @@
         return result;
     }
 
-    public Set<java.util.Map.Entry<Node, Node>> entrySet() {
-        throw new UnsupportedOperationException("Cannot get entry set for this map");
+    public Set<Map.Entry<Node, Node>> entrySet() {
+        HashSet<Map.Entry<Node, Node>> entries = new HashSet<>();
+        for (Map.Entry<Node, Node> entry : entries()) {
+            entries.add(entry);
+        }
+        return entries;
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sat Jan 31 19:03:33 2015 +0100
@@ -210,7 +210,7 @@
             CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
             // create suites everytime, as we modify options for the compiler
             final Suites suitesLocal = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().createSuites();
-            final CompilationResult compResult = compileGraph(graph, null, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
+            final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
                             OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default);
             addMethod(method, compResult);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Sat Jan 31 19:03:33 2015 +0100
@@ -197,7 +197,7 @@
                     HotSpotProviders providers = backend.getProviders();
                     BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess());
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
-                    result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default, optimisticOpts);
+                    result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default, optimisticOpts, providers.getReplacements());
                 } else {
                     Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
                     if (GraalOptions.CacheGraphs.getValue()) {
@@ -230,7 +230,7 @@
                         // all code after the OSR loop is never executed.
                         optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
                     }
-                    result = compileGraph(graph, null, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
+                    result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
                                     method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
                 }
                 result.setId(getId());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Sat Jan 31 19:03:33 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -65,6 +66,15 @@
         HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls();
         final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
 
+        try (InitTimer st = timer("graphBuilderPlugins.initialize")) {
+            GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
+            GraphBuilderPlugins plugins = phase.getGraphBuilderPlugins();
+            Iterable<GraphBuilderPluginsProvider> sl = Services.load(GraphBuilderPluginsProvider.class);
+            for (GraphBuilderPluginsProvider p : sl) {
+                p.registerPlugins(providers.getMetaAccess(), plugins);
+            }
+        }
+
         try (InitTimer st = timer("foreignCalls.initialize")) {
             foreignCalls.initialize(providers, config);
         }
@@ -92,6 +102,5 @@
                 throw Debug.handle(e);
             }
         }
-
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Sat Jan 31 19:03:33 2015 +0100
@@ -66,7 +66,7 @@
         }
         if (obj instanceof HotSpotResolvedJavaField) {
             HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj;
-            if (that.offset != this.offset) {
+            if (that.offset != this.offset || that.isStatic() != this.isStatic()) {
                 return false;
             } else if (this.holder.equals(that.holder)) {
                 assert this.name.equals(that.name) && this.type.equals(that.type);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Sat Jan 31 19:03:33 2015 +0100
@@ -30,7 +30,7 @@
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderConfiguration.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.DebugInfoMode;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
@@ -84,7 +84,7 @@
     protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
-        config.setInlineTrivial(true);
+        config = config.withInlineTrivial(true);
         suite.appendPhase(new GraphBuilderPhase(config));
         return suite;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Sat Jan 31 19:03:33 2015 +0100
@@ -162,7 +162,7 @@
         Suites suites = providers.getSuites().createSuites();
         PhaseSuite<HighTierContext> phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false);
-        CompilationResult compResult = GraalCompiler.compileGraph(g, null, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL,
+        CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL,
                         DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
         InstalledCode installedCode;
         try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,61 @@
+/*
+ * 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.hotspot.replacements;
+
+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.nodes.spi.*;
+
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        plugins.register(metaAccess, ObjectPlugin.class);
+    }
+
+    enum ObjectPlugin implements GraphBuilderPlugin {
+        getClass() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                assert args.length == 1;
+                ValueNode rcvr = args[0];
+                GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr));
+                StampProvider stampProvider = builder.getStampProvider();
+                LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi));
+                HubGetClassNode mirror = builder.append(new HubGetClassNode(builder.getMetaAccess(), hub));
+                builder.push(Kind.Object, mirror);
+                return true;
+            }
+        };
+
+        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/AbstractBytecodeParser.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Sat Jan 31 19:03:33 2015 +0100
@@ -1153,5 +1153,4 @@
         }
         Debug.log("%s", sb);
     }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        plugins.register(metaAccess, ObjectPlugin.class);
+    }
+
+    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));
+                }
+                return true;
+            }
+
+            public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
+                return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, "<init>");
+            }
+        };
+
+        @Override
+        public String toString() {
+            return Object.class.getName() + "." + name() + "()";
+        }
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Sat Jan 31 19:03:33 2015 +0100
@@ -36,7 +36,7 @@
     private final ResolvedJavaType[] skippedExceptionTypes;
     private final DebugInfoMode debugInfoMode;
     private final boolean doLivenessAnalysis;
-    private boolean inlineTrivial;
+    private final boolean inlineTrivial;
 
     public static enum DebugInfoMode {
         SafePointsOnly,
@@ -62,25 +62,35 @@
         Full,
     }
 
-    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis) {
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis,
+                    boolean inlineTrivial) {
         this.eagerResolving = eagerResolving;
         this.omitAllExceptionEdges = omitAllExceptionEdges;
         this.debugInfoMode = debugInfoMode;
         this.skippedExceptionTypes = skippedExceptionTypes;
         this.doLivenessAnalysis = doLivenessAnalysis;
+        this.inlineTrivial = inlineTrivial;
     }
 
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
+    }
+
+    public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
+        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
     }
 
     public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
         ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial);
     }
 
     public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, inlineTrivial);
+    }
+
+    public GraphBuilderConfiguration withInlineTrivial(boolean newInlineTrivial) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newInlineTrivial);
     }
 
     public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -108,19 +118,19 @@
     }
 
     public static GraphBuilderConfiguration getDefault() {
-        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
+        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false);
     }
 
     public static GraphBuilderConfiguration getEagerDefault() {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
+        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false);
     }
 
     public static GraphBuilderConfiguration getSnippetDefault() {
-        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
+        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false);
     }
 
     public static GraphBuilderConfiguration getFullDebugDefault() {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue());
+        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), false);
     }
 
     /**
@@ -135,8 +145,4 @@
     public boolean shouldInlineTrivial() {
         return inlineTrivial;
     }
-
-    public void setInlineTrivial(boolean inlineTrivial) {
-        this.inlineTrivial = inlineTrivial;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object.
+ */
+public interface GraphBuilderContext {
+
+    <T extends ControlSinkNode> T append(T fixed);
+
+    <T extends ControlSplitNode> T append(T fixed);
+
+    <T extends FixedWithNextNode> T append(T fixed);
+
+    <T extends FloatingNode> T append(T v);
+
+    StampProvider getStampProvider();
+
+    MetaAccessProvider getMetaAccess();
+
+    Assumptions getAssumptions();
+
+    void push(Kind kind, ValueNode value);
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sat Jan 31 19:03:33 2015 +0100
@@ -47,6 +47,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -58,20 +59,26 @@
 public class GraphBuilderPhase extends BasePhase<HighTierContext> {
 
     private final GraphBuilderConfiguration graphBuilderConfig;
+    private final GraphBuilderPlugins graphBuilderPlugins;
 
-    public GraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfig) {
-        this.graphBuilderConfig = graphBuilderConfig;
+    public GraphBuilderPhase(GraphBuilderConfiguration config) {
+        this.graphBuilderConfig = config;
+        this.graphBuilderPlugins = new GraphBuilderPlugins();
     }
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), graphBuilderConfig, context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), graphBuilderConfig, graphBuilderPlugins, context.getOptimisticOptimizations()).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
         return graphBuilderConfig;
     }
 
+    public GraphBuilderPlugins getGraphBuilderPlugins() {
+        return graphBuilderPlugins;
+    }
+
     public static class Instance extends Phase {
 
         protected StructuredGraph currentGraph;
@@ -81,7 +88,10 @@
         private ResolvedJavaMethod rootMethod;
 
         private final GraphBuilderConfiguration graphBuilderConfig;
+        private final GraphBuilderPlugins graphBuilderPlugins;
         private final OptimisticOptimizations optimisticOpts;
+        private final StampProvider stampProvider;
+        private final Assumptions assumptions;
 
         /**
          * Gets the graph being processed by this builder.
@@ -90,13 +100,21 @@
             return currentGraph;
         }
 
-        public Instance(MetaAccessProvider metaAccess, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins,
+                        OptimisticOptimizations optimisticOpts) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
+            this.stampProvider = stampProvider;
+            this.assumptions = assumptions;
+            this.graphBuilderPlugins = graphBuilderPlugins;
             assert metaAccess != null;
         }
 
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+            this(metaAccess, stampProvider, assumptions, graphBuilderConfig, null, optimisticOpts);
+        }
+
         @Override
         protected void run(StructuredGraph graph) {
             ResolvedJavaMethod method = graph.method();
@@ -143,7 +161,7 @@
             }
         }
 
-        public class BytecodeParser extends AbstractBytecodeParser<ValueNode, HIRFrameStateBuilder> {
+        public class BytecodeParser extends AbstractBytecodeParser<ValueNode, HIRFrameStateBuilder> implements GraphBuilderContext {
 
             private BciBlock[] loopHeaders;
             private LocalLiveness liveness;
@@ -752,38 +770,49 @@
                         args[0] = TypeProfileProxyNode.proxify(args[0], profile);
                     }
                 }
+                if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect()) {
 
-                if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect() && targetMethod.canBeInlined() && targetMethod.hasBytecodes()) {
-                    if (targetMethod.getCode().length <= GraalOptions.TrivialInliningSize.getValue() && currentDepth < GraalOptions.InlineDuringParsingMaxDepth.getValue() &&
-                                    graphBuilderConfig.shouldInlineTrivial()) {
-                        BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, StructuredGraph.INVOCATION_ENTRY_BCI);
-                        final FrameState[] lazyFrameState = new FrameState[1];
-                        HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, () -> {
-                            if (lazyFrameState[0] == null) {
-                                lazyFrameState[0] = frameState.create(bci());
-                            }
-                            return lazyFrameState[0];
-                        });
-                        startFrameState.initializeFromArgumentsArray(args);
-                        parser.build(currentDepth + 1, this.lastInstr, startFrameState);
-
-                        FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
-                        this.lastInstr = calleeBeforeReturnNode;
-                        if (calleeBeforeReturnNode != null) {
-                            ValueNode calleeReturnValue = parser.getReturnValue();
-                            if (calleeReturnValue != null) {
-                                frameState.push(calleeReturnValue.getKind().getStackKind(), calleeReturnValue);
+                    if (graphBuilderPlugins != null) {
+                        GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod);
+                        if (plugin != null) {
+                            if (plugin.handleInvocation(this, args)) {
+                                return;
                             }
                         }
+                    }
 
-                        FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
-                        if (calleeBeforeUnwindNode != null) {
-                            ValueNode calleeUnwindValue = parser.getUnwindValue();
-                            assert calleeUnwindValue != null;
-                            calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+                    if (targetMethod.canBeInlined() && targetMethod.hasBytecodes()) {
+                        if (targetMethod.getCode().length <= GraalOptions.TrivialInliningSize.getValue() && currentDepth < GraalOptions.InlineDuringParsingMaxDepth.getValue() &&
+                                        graphBuilderConfig.shouldInlineTrivial()) {
+                            BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, StructuredGraph.INVOCATION_ENTRY_BCI);
+                            final FrameState[] lazyFrameState = new FrameState[1];
+                            HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, () -> {
+                                if (lazyFrameState[0] == null) {
+                                    lazyFrameState[0] = frameState.create(bci());
+                                }
+                                return lazyFrameState[0];
+                            });
+                            startFrameState.initializeFromArgumentsArray(args);
+                            parser.build(currentDepth + 1, this.lastInstr, startFrameState);
+
+                            FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
+                            this.lastInstr = calleeBeforeReturnNode;
+                            if (calleeBeforeReturnNode != null) {
+                                ValueNode calleeReturnValue = parser.getReturnValue();
+                                if (calleeReturnValue != null) {
+                                    frameState.push(calleeReturnValue.getKind().getStackKind(), calleeReturnValue);
+                                }
+                            }
+
+                            FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
+                            if (calleeBeforeUnwindNode != null) {
+                                ValueNode calleeUnwindValue = parser.getUnwindValue();
+                                assert calleeUnwindValue != null;
+                                calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+                            }
+
+                            return;
                         }
-
-                        return;
                     }
                 }
 
@@ -937,7 +966,7 @@
                 throw GraalInternalError.shouldNotReachHere("Can not append Node of type: " + v.getClass().getName());
             }
 
-            private <T extends ControlSinkNode> T append(T fixed) {
+            public <T extends ControlSinkNode> T append(T fixed) {
                 assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
                 assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
                 T added = currentGraph.add(fixed);
@@ -946,7 +975,7 @@
                 return added;
             }
 
-            private <T extends ControlSplitNode> T append(T fixed) {
+            public <T extends ControlSplitNode> T append(T fixed) {
                 assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
                 assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
                 T added = currentGraph.add(fixed);
@@ -955,7 +984,7 @@
                 return added;
             }
 
-            protected <T extends FixedWithNextNode> T append(T fixed) {
+            public <T extends FixedWithNextNode> T append(T fixed) {
                 assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
                 assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
                 T added = currentGraph.add(fixed);
@@ -964,7 +993,7 @@
                 return added;
             }
 
-            private <T extends FloatingNode> T append(T v) {
+            public <T extends FloatingNode> T append(T v) {
                 assert !(v instanceof ConstantNode);
                 T added = currentGraph.unique(v);
                 return added;
@@ -1456,6 +1485,22 @@
                 append(ifNode);
             }
 
+            public StampProvider getStampProvider() {
+                return stampProvider;
+            }
+
+            public MetaAccessProvider getMetaAccess() {
+                return metaAccess;
+            }
+
+            public Assumptions getAssumptions() {
+                return assumptions;
+            }
+
+            public void push(Kind kind, ValueNode value) {
+                frameState.push(kind, value);
+            }
+
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Extensions for handling certain bytecode instructions while building a
+ * {@linkplain StructuredGraph graph} from a bytecode stream.
+ */
+public interface GraphBuilderPlugin {
+
+    /**
+     * Processes an invocation parsed in a bytecode stream and add nodes to a graph being
+     * constructed that implement the semantics of the invocation.
+     *
+     * @param builder object being used to build a graph
+     * @param args the arguments to the invocation
+     */
+    boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args);
+
+    /**
+     * Gets the target method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])}
+     * .
+     */
+    ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess);
+
+    static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class<?> clazz, String methodName, Class<?>... parameterTypes) {
+        try {
+            return metaAccess.lookupJavaMethod(methodName.equals("<init>") ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getDeclaredMethod(methodName, parameterTypes));
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * A repository of {@link GraphBuilderPlugin}s.
+ */
+public class GraphBuilderPlugins {
+
+    private final Map<ResolvedJavaMethod, GraphBuilderPlugin> map = new HashMap<>();
+
+    /**
+     * Registers all the constants of an enum that implements {@link GraphBuilderPlugin}.
+     */
+    public <T extends Enum<T> & GraphBuilderPlugin> void register(MetaAccessProvider metaAccess, Class<T> enumClass) {
+        assert Enum.class.isAssignableFrom(enumClass);
+        Object[] enumConstants = enumClass.getEnumConstants();
+        for (Object o : enumConstants) {
+            GraphBuilderPlugin gbp = (GraphBuilderPlugin) o;
+            ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess);
+            GraphBuilderPlugin oldValue = map.put(target, gbp);
+            assert oldValue == null;
+        }
+    }
+
+    /**
+     * Gets the plugin for a given method registered in the object.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public GraphBuilderPlugin getPlugin(ResolvedJavaMethod method) {
+        return map.get(method);
+    }
+
+    @Override
+    public String toString() {
+        return map.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+
+/**
+ * Interface for providers of {@link GraphBuilderPlugin}s.
+ */
+public interface GraphBuilderPluginsProvider extends Service {
+    /**
+     * Registers the plugins provided by this object with a plugins registry.
+     *
+     * @param plugins registry of plugins
+     */
+    void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins);
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMapBuilder.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMapBuilder.java	Sat Jan 31 19:03:33 2015 +0100
@@ -36,14 +36,14 @@
      * runtime for walking/inspecting frames of such methods.
      */
     public StackSlot allocateRBPSpillSlot() {
-        return ((AMD64FrameMap) frameMap).allocateRBPSpillSlot();
+        return ((AMD64FrameMap) getFrameMap()).allocateRBPSpillSlot();
     }
 
     public void freeRBPSpillSlot() {
-        ((AMD64FrameMap) frameMap).freeRBPSpillSlot();
+        ((AMD64FrameMap) getFrameMap()).freeRBPSpillSlot();
     }
 
     public StackSlot allocateDeoptimizationRescueSlot() {
-        return ((AMD64FrameMap) frameMap).allocateDeoptimizationRescueSlot();
+        return ((AMD64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot();
     }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMapBuilder.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMapBuilder.java	Sat Jan 31 19:03:33 2015 +0100
@@ -32,6 +32,6 @@
     }
 
     public StackSlot allocateDeoptimizationRescueSlot() {
-        return ((SPARCFrameMap) frameMap).allocateDeoptimizationRescueSlot();
+        return ((SPARCFrameMap) getFrameMap()).allocateDeoptimizationRescueSlot();
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Sat Jan 31 19:03:33 2015 +0100
@@ -22,24 +22,18 @@
  */
 package com.oracle.graal.lir;
 
-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.debug.Debug.Scope;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.framemap.*;
 
 /**
  * This class implements the overall container for the LIR graph and directs its construction,
  * optimization, and finalization.
  */
-public class LIR implements FrameMappable {
+public class LIR {
 
     private final AbstractControlFlowGraph<?> cfg;
 
@@ -226,30 +220,4 @@
         }
     }
 
-    public void map(FrameMappingTool tool) {
-        try (Scope scope = Debug.scope("StackSlotMappingLIR")) {
-            ValueProcedure updateProc = (value, mode, flags) -> {
-                if (isVirtualStackSlot(value)) {
-                    StackSlot stackSlot = tool.getStackSlot(asVirtualStackSlot(value));
-                    Debug.log("map %s -> %s", value, stackSlot);
-                    return stackSlot;
-                }
-                return value;
-            };
-            for (AbstractBlock<?> block : getControlFlowGraph().getBlocks()) {
-                try (Indent indent0 = Debug.logAndIndent("block: %s", block)) {
-                    for (LIRInstruction inst : getLIRforBlock(block)) {
-                        try (Indent indent1 = Debug.logAndIndent("Inst: %d: %s", inst.id(), inst)) {
-                            inst.forEachAlive(updateProc);
-                            inst.forEachInput(updateProc);
-                            inst.forEachOutput(updateProc);
-                            inst.forEachTemp(updateProc);
-                            inst.forEachState(updateProc);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java	Sat Jan 31 19:03:33 2015 +0100
@@ -256,7 +256,7 @@
      * @param kind The kind of the spill slot to be reserved.
      * @return A spill slot denoting the reserved memory area.
      */
-    protected StackSlot allocateSpillSlot(LIRKind kind) {
+    public StackSlot allocateSpillSlot(LIRKind kind) {
         assert frameSize == -1 : "frame size must not yet be fixed";
         int size = spillSlotSize(kind);
         spillSize = NumUtil.roundUp(spillSize + size, size);
@@ -264,6 +264,16 @@
     }
 
     /**
+     * Returns the size of the stack slot range for {@code slots} objects.
+     *
+     * @param slots The number of slots.
+     * @return The size in byte
+     */
+    public int spillSlotRangeSize(int slots) {
+        return slots * getTarget().wordSize;
+    }
+
+    /**
      * Reserves a number of contiguous slots in the frame of the method being compiled. If the
      * requested number of slots is 0, this method returns {@code null}.
      *
@@ -274,12 +284,12 @@
      *            collector could see garbage object values.
      * @return the first reserved stack slot (i.e., at the lowest address)
      */
-    protected StackSlot allocateStackSlots(int slots, BitSet objects) {
+    public StackSlot allocateStackSlots(int slots, BitSet objects) {
         assert frameSize == -1 : "frame size must not yet be fixed";
         if (slots == 0) {
             return null;
         }
-        spillSize += (slots * getTarget().wordSize);
+        spillSize += spillSlotRangeSize(slots);
 
         if (!objects.isEmpty()) {
             assert objects.length() <= slots;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilder.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilder.java	Sat Jan 31 19:03:33 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 
 /**
  * A {@link FrameMapBuilder} is used to collect all information necessary to
@@ -72,14 +73,8 @@
     void callsMethod(CallingConvention cc);
 
     /**
-     * Registers a FrameMappable class so that virtual stack slots can be changed to real stack
-     * slots.
-     */
-    void requireMapping(FrameMappable mappable);
-
-    /**
      * Creates a {@linkplain FrameMap} based on the information collected by this
      * {@linkplain FrameMapBuilder}.
      */
-    FrameMap buildFrameMap(LIRGenerationResult result);
+    FrameMap buildFrameMap(LIRGenerationResult result, StackSlotAllocator allocator);
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java	Sat Jan 31 19:03:33 2015 +0100
@@ -27,16 +27,19 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 
 /**
  * A FrameMapBuilder that records allocation.
  */
-public class FrameMapBuilderImpl implements FrameMapBuilder {
+public class FrameMapBuilderImpl implements FrameMapBuilderTool {
 
     private final RegisterConfig registerConfig;
     private final CodeCacheProvider codeCache;
-    protected final FrameMap frameMap;
+    private final FrameMap frameMap;
     private final List<VirtualStackSlot> stackSlots;
     private final List<CallingConvention> calls;
     private int numStackSlots;
@@ -48,12 +51,9 @@
         this.frameMap = frameMap;
         this.stackSlots = new ArrayList<>();
         this.calls = new ArrayList<>();
-        this.mappables = new ArrayList<>();
         this.numStackSlots = 0;
     }
 
-    private final List<FrameMappable> mappables;
-
     public VirtualStackSlot allocateSpillSlot(LIRKind kind) {
         SimpleVirtualStackSlot slot = new SimpleVirtualStackSlot(numStackSlots++, kind);
         stackSlots.add(slot);
@@ -80,10 +80,10 @@
         return codeCache;
     }
 
-    /**
-     * Returns the number of {@link VirtualStackSlot}s created by this {@link FrameMapBuilder}. Can
-     * be used as an upper bound for an array indexed by {@link VirtualStackSlot#getId()}.
-     */
+    public FrameMap getFrameMap() {
+        return frameMap;
+    }
+
     public int getNumberOfStackSlots() {
         return numStackSlots;
     }
@@ -92,23 +92,18 @@
         calls.add(cc);
     }
 
-    public FrameMap buildFrameMap(LIRGenerationResult res) {
-        FrameMappingTool mapper = new SimpleStackSlotAllocator().allocateStackSlots(this);
+    public FrameMap buildFrameMap(LIRGenerationResult res, StackSlotAllocator allocator) {
+        try (Scope s = Debug.scope("StackSlotAllocation")) {
+            allocator.allocateStackSlots(this, res);
+        }
         for (CallingConvention cc : calls) {
             frameMap.callsMethod(cc);
         }
-        // rewrite
-        mappables.forEach(m -> m.map(mapper));
-
         frameMap.finish();
         return frameMap;
     }
 
-    public void requireMapping(FrameMappable mappable) {
-        this.mappables.add(mappable);
-    }
-
-    List<VirtualStackSlot> getStackSlots() {
+    public List<VirtualStackSlot> getStackSlots() {
         return stackSlots;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderTool.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2014, 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.framemap;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+
+/**
+ * A {@link FrameMapBuilder} that allows access to the underlying {@link FrameMap}.
+ */
+public interface FrameMapBuilderTool extends FrameMapBuilder {
+
+    /**
+     * Returns the number of {@link VirtualStackSlot}s created by this {@link FrameMapBuilder}. Can
+     * be used as an upper bound for an array indexed by {@link VirtualStackSlot#getId()}.
+     */
+    int getNumberOfStackSlots();
+
+    List<VirtualStackSlot> getStackSlots();
+
+    FrameMap getFrameMap();
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappable.java	Wed Jan 28 15:07:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.framemap;
-
-/**
- * This interface should be implemented by all classes that store virtual stack slots to convert
- * them into real stack slots when {@link FrameMapBuilder#buildFrameMap} is called. Implementors
- * should register themselves using {@link FrameMapBuilder#requireMapping(FrameMappable)}.
- */
-public interface FrameMappable {
-    void map(FrameMappingTool tool);
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMappingTool.java	Wed Jan 28 15:07:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.framemap;
-
-import com.oracle.graal.api.code.*;
-
-/**
- * A tool to get the real stack slot from a virtual stack slot.
- */
-@FunctionalInterface
-public interface FrameMappingTool {
-    StackSlot getStackSlot(VirtualStackSlot slot);
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleStackSlotAllocator.java	Wed Jan 28 15:07:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.framemap;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.*;
-
-public class SimpleStackSlotAllocator implements StackSlotAllocator {
-
-    public FrameMappingTool allocateStackSlots(FrameMapBuilderImpl builder) {
-        StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()];
-        for (VirtualStackSlot virtualSlot : builder.getStackSlots()) {
-            final StackSlot slot;
-            if (virtualSlot instanceof SimpleVirtualStackSlot) {
-                slot = mapSimpleVirtualStackSlot(builder, (SimpleVirtualStackSlot) virtualSlot);
-            } else if (virtualSlot instanceof VirtualStackSlotRange) {
-                slot = mapVirtualStackSlotRange(builder, (VirtualStackSlotRange) virtualSlot);
-            } else {
-                throw GraalInternalError.shouldNotReachHere("Unknown VirtualStackSlot: " + virtualSlot);
-            }
-            mapping[virtualSlot.getId()] = slot;
-        }
-        return v -> mapping[v.getId()];
-    }
-
-    protected StackSlot mapSimpleVirtualStackSlot(FrameMapBuilderImpl builder, SimpleVirtualStackSlot virtualStackSlot) {
-        return builder.frameMap.allocateSpillSlot(virtualStackSlot.getLIRKind());
-    }
-
-    protected StackSlot mapVirtualStackSlotRange(FrameMapBuilderImpl builder, VirtualStackSlotRange virtualStackSlot) {
-        return builder.frameMap.allocateStackSlots(virtualStackSlot.getSlots(), virtualStackSlot.getObjects());
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java	Sat Jan 31 19:03:33 2015 +0100
@@ -28,7 +28,7 @@
 /**
  * Represents a {@link VirtualStackSlot virtual stack slot} for a specific {@link LIRKind kind}.
  */
-class SimpleVirtualStackSlot extends VirtualStackSlot {
+public class SimpleVirtualStackSlot extends VirtualStackSlot {
 
     private static final long serialVersionUID = 7654295701165421750L;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/StackSlotAllocator.java	Wed Jan 28 15:07:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.framemap;
-
-import com.oracle.graal.api.code.*;
-
-/**
- * A {@link StackSlotAllocator} is responsible for translating {@link VirtualStackSlot virtual}
- * stack slots into {@link StackSlot real} stack slots.
- */
-public interface StackSlotAllocator {
-    FrameMappingTool allocateStackSlots(FrameMapBuilderImpl builder);
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java	Sat Jan 31 19:03:33 2015 +0100
@@ -31,7 +31,7 @@
  * Represents a {@link #getSlots() numbered} range of {@link VirtualStackSlot virtual stack slot} of
  * size {@link TargetDescription#wordSize}.
  */
-class VirtualStackSlotRange extends VirtualStackSlot {
+public class VirtualStackSlotRange extends VirtualStackSlot {
 
     private static final long serialVersionUID = 5152592950118317121L;
     private final BitSet objects;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Sat Jan 31 19:03:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 
 public interface LIRGenerationResult {
 
@@ -31,7 +32,7 @@
      * Returns the {@link FrameMapBuilder} for collecting the information to build a
      * {@link FrameMap}.
      *
-     * This method can only be used prior calling {@link #buildFrameMap()}.
+     * This method can only be used prior calling {@link #buildFrameMap}.
      */
     FrameMapBuilder getFrameMapBuilder();
 
@@ -41,12 +42,12 @@
      *
      * @see FrameMapBuilder#buildFrameMap
      */
-    void buildFrameMap();
+    void buildFrameMap(StackSlotAllocator allocator);
 
     /**
      * Returns the {@link FrameMap} associated with this {@link LIRGenerationResult}.
      *
-     * This method can only be called after {@link #buildFrameMap()}.
+     * This method can only be called after {@link #buildFrameMap}.
      */
     FrameMap getFrameMap();
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Sat Jan 31 19:03:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 
 public class LIRGenerationResultBase implements LIRGenerationResult {
     private final LIR lir;
@@ -59,9 +60,9 @@
         return frameMapBuilder;
     }
 
-    public void buildFrameMap() {
+    public void buildFrameMap(StackSlotAllocator allocator) {
         assert frameMap == null : "buildFrameMap() can only be called once!";
-        frameMap = frameMapBuilder.buildFrameMap(this);
+        frameMap = frameMapBuilder.buildFrameMap(this, allocator);
     }
 
     public FrameMap getFrameMap() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,104 @@
+/*
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,524 @@
+/*
+ * 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.ValueUtil.*;
+
+import java.util.*;
+import java.util.function.*;
+
+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.debug.Debug.Scope;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.options.*;
+
+/**
+ * Linear Scan {@link StackSlotAllocator}.
+ * <p>
+ * <b>Remark:</b> The analysis works under the assumption that a stack slot is no longer live after
+ * its last usage. If an {@link LIRInstruction instruction} transfers the raw address of the stack
+ * slot to another location, e.g. a registers, and this location is referenced later on, the
+ * {@link com.oracle.graal.lir.LIRInstruction.Use usage} of the stack slot must be marked with the
+ * {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content
+ * destroyed.
+ */
+public final class LSStackSlotAllocator implements StackSlotAllocator {
+
+    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);
+        // @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 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 Allocator(LIR lir, FrameMapBuilderTool frameMapBuilder) {
+            this.lir = lir;
+            this.frameMapBuilder = frameMapBuilder;
+            this.stackSlotMap = new StackInterval[frameMapBuilder.getNumberOfStackSlots()];
+        }
+
+        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();
+            try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals")) {
+                buildIntervalsSlow();
+            }
+            if (Debug.isEnabled()) {
+                verifyIntervals();
+            }
+            if (Debug.isDumpEnabled()) {
+                dumpIntervals("Before stack slot allocation");
+            }
+            // allocate stack slots
+            allocateStackSlots();
+            if (Debug.isDumpEnabled()) {
+                dumpIntervals("After stack slot allocation");
+            }
+
+            // 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());
+                }
+
+            }
+        }
+
+        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;
+        }
+
+        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 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;
+        }
+
+        private void verifyIntervals() {
+            forEachInterval(interval -> {
+                assert interval.verify(this);
+            });
+        }
+
+        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());
+        }
+
+        private void allocateStackSlots() {
+            // create interval lists
+            createUnhandled();
+
+            for (StackInterval current = activateNext(); current != null; current = activateNext()) {
+                try (Indent indent = Debug.logAndIndent("allocate %s", current)) {
+                    allocateSlot(current);
+                }
+            }
+
+        }
+
+        private void allocateSlot(StackInterval current) {
+            VirtualStackSlot virtualSlot = current.getOperand();
+            final StackSlot location;
+            if (virtualSlot instanceof VirtualStackSlotRange) {
+                // No reuse of ranges (yet).
+                VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot;
+                location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots(), slotRange.getObjects());
+                StackSlotAllocator.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots()));
+                StackSlotAllocator.allocatedSlots.increment();
+            } else {
+                assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpexted VirtualStackSlot type: " + virtualSlot;
+                StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot);
+                if (slot != null) {
+                    /*
+                     * Free stack slot available. Note that we create a new one because the kind
+                     * might not match.
+                     */
+                    location = StackSlot.get(current.kind(), slot.getRawOffset(), slot.getRawAddFrameSize());
+                    StackSlotAllocator.reusedSlots.increment();
+                    Debug.log(1, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot);
+                } else {
+                    // Allocate new stack slot.
+                    location = frameMapBuilder.getFrameMap().allocateSpillSlot(virtualSlot.getLIRKind());
+                    StackSlotAllocator.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotSize(virtualSlot.getLIRKind()));
+                    StackSlotAllocator.allocatedSlots.increment();
+                    Debug.log(1, "New stack slot %s for virtual stack slot %s", location, virtualSlot);
+                }
+            }
+            Debug.log("Allocate location %s for interval %s", location, current);
+            current.setLocation(location);
+        }
+
+        private static enum SlotSize {
+            Size1,
+            Size2,
+            Size4,
+            Size8,
+            Illegal;
+        }
+
+        private SlotSize forKind(LIRKind kind) {
+            switch (frameMapBuilder.getFrameMap().spillSlotSize(kind)) {
+                case 1:
+                    return SlotSize.Size1;
+                case 2:
+                    return SlotSize.Size2;
+                case 4:
+                    return SlotSize.Size4;
+                case 8:
+                    return SlotSize.Size8;
+                default:
+                    return SlotSize.Illegal;
+            }
+        }
+
+        private EnumMap<SlotSize, LinkedList<StackSlot>> freeSlots = new EnumMap<>(SlotSize.class);
+
+        private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) {
+            assert slot != null;
+            SlotSize size = forKind(slot.getLIRKind());
+            LinkedList<StackSlot> freeList = size == SlotSize.Illegal ? null : freeSlots.get(size);
+            if (freeList == null) {
+                return null;
+            }
+            return freeList.pollFirst();
+        }
+
+        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);
+        }
+
+        private StackInterval activateNext() {
+            if (unhandled.isEmpty()) {
+                return null;
+            }
+            StackInterval next = unhandled.pollFirst();
+            for (int id = next.from(); activePeekId() < id;) {
+                finished(active.pollFirst());
+            }
+            Debug.log("activte %s", next);
+            insertSortedByTo(next);
+            return next;
+        }
+
+        private int activePeekId() {
+            StackInterval first = active.peekFirst();
+            if (first == null) {
+                return Integer.MAX_VALUE;
+            }
+            return first.to();
+        }
+
+        private void finished(StackInterval interval) {
+            StackSlot location = interval.location();
+            Debug.log("finished %s (freeing %s)", interval, location);
+            freeSlot(location);
+        }
+
+        private void assignStackSlots() {
+            for (AbstractBlock<?> block : sortedBlocks) {
+                lir.getLIRforBlock(block).forEach(op -> {
+                    op.forEachInput(this::assignSlot);
+                    op.forEachAlive(this::assignSlot);
+                    op.forEachState(this::assignSlot);
+
+                    op.forEachTemp(this::assignSlot);
+                    op.forEachOutput(this::assignSlot);
+                });
+            }
+        }
+
+        /**
+         * @see ValueProcedure
+         * @param value
+         * @param mode
+         * @param flags
+         */
+        private Value assignSlot(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isVirtualStackSlot(value)) {
+                VirtualStackSlot slot = asVirtualStackSlot(value);
+                StackInterval interval = get(slot);
+                assert interval != null;
+                return interval.location();
+            }
+            return value;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,93 @@
+/*
+ * 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.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+
+public class SimpleStackSlotAllocator implements StackSlotAllocator {
+
+    public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
+        StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()];
+        long currentFrameSize = Debug.isMeterEnabled() ? builder.getFrameMap().currentFrameSize() : 0;
+        for (VirtualStackSlot virtualSlot : builder.getStackSlots()) {
+            final StackSlot slot;
+            if (virtualSlot instanceof SimpleVirtualStackSlot) {
+                slot = mapSimpleVirtualStackSlot(builder, (SimpleVirtualStackSlot) virtualSlot);
+                virtualFramesize.add(builder.getFrameMap().spillSlotSize(virtualSlot.getLIRKind()));
+            } else if (virtualSlot instanceof VirtualStackSlotRange) {
+                VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot;
+                slot = mapVirtualStackSlotRange(builder, slotRange);
+                virtualFramesize.add(builder.getFrameMap().spillSlotRangeSize(slotRange.getSlots()));
+            } else {
+                throw GraalInternalError.shouldNotReachHere("Unknown VirtualStackSlot: " + virtualSlot);
+            }
+            allocatedSlots.increment();
+            mapping[virtualSlot.getId()] = slot;
+        }
+        updateLIR(res, mapping);
+        allocatedFramesize.add(builder.getFrameMap().currentFrameSize() - currentFrameSize);
+    }
+
+    protected void updateLIR(LIRGenerationResult res, StackSlot[] mapping) {
+        try (Scope scope = Debug.scope("StackSlotMappingLIR")) {
+            ValueProcedure updateProc = (value, mode, flags) -> {
+                if (isVirtualStackSlot(value)) {
+                    StackSlot stackSlot = mapping[asVirtualStackSlot(value).getId()];
+                    Debug.log("map %s -> %s", value, stackSlot);
+                    return stackSlot;
+                }
+                return value;
+            };
+            for (AbstractBlock<?> block : res.getLIR().getControlFlowGraph().getBlocks()) {
+                try (Indent indent0 = Debug.logAndIndent("block: %s", block)) {
+                    for (LIRInstruction inst : res.getLIR().getLIRforBlock(block)) {
+                        try (Indent indent1 = Debug.logAndIndent("Inst: %d: %s", inst.id(), inst)) {
+                            inst.forEachAlive(updateProc);
+                            inst.forEachInput(updateProc);
+                            inst.forEachOutput(updateProc);
+                            inst.forEachTemp(updateProc);
+                            inst.forEachState(updateProc);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected StackSlot mapSimpleVirtualStackSlot(FrameMapBuilderTool builder, SimpleVirtualStackSlot virtualStackSlot) {
+        return builder.getFrameMap().allocateSpillSlot(virtualStackSlot.getLIRKind());
+    }
+
+    protected StackSlot mapVirtualStackSlotRange(FrameMapBuilderTool builder, VirtualStackSlotRange virtualStackSlot) {
+        return builder.getFrameMap().allocateStackSlots(virtualStackSlot.getSlots(), virtualStackSlot.getObjects());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,134 @@
+/*
+ * 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 com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+
+public class StackInterval {
+
+    private static final int INVALID_START = Integer.MAX_VALUE;
+    private static final int INVALID_END = Integer.MIN_VALUE;
+    private final VirtualStackSlot operand;
+    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());
+        return true;
+    }
+
+    public VirtualStackSlot getOperand() {
+        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;
+        }
+    }
+
+    protected void addFrom(int opId) {
+        if (from > opId) {
+            from = opId;
+            // set opId also as to if it has not yet been set
+            if (to == INVALID_END) {
+                to = opId;
+            }
+        }
+    }
+
+    public LIRKind kind() {
+        return kind;
+    }
+
+    public StackSlot location() {
+        return location;
+    }
+
+    public void setLocation(StackSlot location) {
+        this.location = location;
+    }
+
+    public StackInterval locationHint() {
+        return null;
+    }
+
+    public int from() {
+        return from;
+    }
+
+    public int to() {
+        return to;
+    }
+
+    public StackUsePosList usePosList() {
+        return usePos;
+    }
+
+    public void fixFrom() {
+        if (from == INVALID_START) {
+            from = 0;
+        }
+    }
+
+    public boolean isFixed() {
+        return from == 0;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("SI[%d-%d] k=%s o=%s l=%s", from, to, kind, operand, location);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackSlotAllocator.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,53 @@
+/*
+ * 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 com.oracle.graal.api.code.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+
+/**
+ * A {@link StackSlotAllocator} is responsible for translating {@link VirtualStackSlot virtual}
+ * stack slots into {@link StackSlot real} stack slots. This includes changing all occurrences of
+ * {@link VirtualStackSlot} in the {@link LIRGenerationResult#getLIR() LIR} to {@link StackSlot}.
+ */
+public interface StackSlotAllocator {
+    /**
+     * The number of allocated stack slots.
+     */
+    DebugMetric allocatedSlots = Debug.metric("StackSlotAllocator[allocatedSlots]");
+    /**
+     * The number of reused stack slots.
+     */
+    DebugMetric reusedSlots = Debug.metric("StackSlotAllocator[reusedSlots]");
+    /**
+     * The size (in bytes) required for all allocated stack slots. Note that this number corresponds
+     * to the actual frame size and might include alignment.
+     */
+    DebugMetric allocatedFramesize = Debug.metric("StackSlotAllocator[AllocatedFramesize]");
+    /** The size (in bytes) required for all virtual stack slots. */
+    DebugMetric virtualFramesize = Debug.metric("StackSlotAllocator[VirtualFramesize]");
+
+    void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,101 @@
+/*
+ * 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/InductionVariables.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Sat Jan 31 19:03:33 2015 +0100
@@ -74,6 +74,13 @@
                 if (loop.isOutsideLoop(op)) {
                     continue;
                 }
+                if (op.usages().count() == 1 && op.usages().first() == baseIvNode) {
+                    /*
+                     * This is just the base induction variable increment with no other uses so
+                     * don't bother reporting it.
+                     */
+                    continue;
+                }
                 InductionVariable iv = null;
                 ValueNode offset = addSub(op, baseIvNode);
                 ValueNode scale;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Sat Jan 31 19:03:33 2015 +0100
@@ -70,13 +70,13 @@
     @Override
     public void lower(LoweringTool tool) {
         /*
-         * Don't allow guards with action None to float. In cases where 2 guards are testing
-         * equivalent conditions they might be lowered at the same location. If the guard with the
-         * None action is lowered before the the other guard then the code will be stuck repeatedly
-         * deoptimizing without invalidating the code. Conditional elimination will eliminate the
-         * guard if it's truly redundant in this case.
+         * Don't allow guards with action None and reason RuntimeConstraint to float. In cases where
+         * 2 guards are testing equivalent conditions they might be lowered at the same location. If
+         * the guard with the None action is lowered before the the other guard then the code will
+         * be stuck repeatedly deoptimizing without invalidating the code. Conditional elimination
+         * will eliminate the guard if it's truly redundant in this case.
          */
-        if (graph().getGuardsStage().allowsFloatingGuards() && getAction() != DeoptimizationAction.None) {
+        if (graph().getGuardsStage().allowsFloatingGuards() && (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint)) {
             ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode();
             this.replaceAtUsages(guard);
             ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.debug;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This node prevents control flow optimizations. It is never duplicated or merged with other
+ * control flow anchors.
+ */
+@NodeInfo
+public class ControlFlowAnchorNode extends FixedWithNextNode implements LIRLowerable {
+
+    private static class Unique {
+    }
+
+    protected Unique unique;
+
+    public ControlFlowAnchorNode(@SuppressWarnings("unused") Invoke invoke) {
+        super(StampFactory.forVoid());
+        this.unique = new Unique();
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        // do nothing
+    }
+}
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Sat Jan 31 19:03:33 2015 +0100
@@ -37,6 +37,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -560,6 +561,46 @@
         out.println();
     }
 
+    public void printStackIntervals(String label, StackInterval[] intervals) {
+        begin("intervals");
+        out.println(String.format("name \"%s\"", label));
+
+        for (StackInterval interval : intervals) {
+            if (interval != null) {
+                printStackInterval(interval);
+            }
+        }
+
+        end("intervals");
+    }
+
+    private void printStackInterval(StackInterval interval) {
+        out.printf("%s %s ", interval.getOperand(), interval.isFixed() ? "fixed" : interval.kind().getPlatformKind());
+        if (interval.location() != null) {
+            out.printf("\"[%s|%c]\"", interval.location(), interval.location().getKind().getTypeChar());
+        } else {
+            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("[%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.println();
+    }
+
     public void printSchedule(String message, SchedulePhase theSchedule) {
         schedule = theSchedule;
         cfg = schedule.getCFG();
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Sat Jan 31 19:03:33 2015 +0100
@@ -35,6 +35,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.stackslotalloc.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.schedule.*;
@@ -181,7 +182,8 @@
             cfgPrinter.printMachineCode(codeCache.disassemble((CompilationResult) tuple[0], (InstalledCode) tuple[1]), message);
         } else if (object instanceof Interval[]) {
             cfgPrinter.printIntervals(message, (Interval[]) object);
-
+        } else if (object instanceof StackInterval[]) {
+            cfgPrinter.printStackIntervals(message, (StackInterval[]) object);
         }
 
         cfgPrinter.target = null;
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java	Sat Jan 31 19:03:33 2015 +0100
@@ -23,6 +23,8 @@
 package com.oracle.graal.replacements.verifier;
 
 import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
 
 import javax.annotation.processing.*;
 import javax.lang.model.element.*;
@@ -46,6 +48,14 @@
         if (value == null) {
             return null;
         }
+        if (expectedType.isArray()) {
+            ArrayList<Object> result = new ArrayList<>();
+            List<AnnotationValue> l = (List<AnnotationValue>) value.getValue();
+            for (AnnotationValue el : l) {
+                result.add(resolveAnnotationValue(expectedType.getComponentType(), el));
+            }
+            return (T) result.toArray((Object[]) Array.newInstance(expectedType.getComponentType(), result.size()));
+        }
         Object unboxedValue = value.getValue();
         if (unboxedValue != null) {
             if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/ClassSubstitutionVerifier.java	Sat Jan 31 19:03:33 2015 +0100
@@ -36,7 +36,6 @@
     private static final String TYPE_VALUE = "value";
     private static final String STRING_VALUE = "className";
     private static final String OPTIONAL = "optional";
-    private static final String STRING_VALUE_DEFAULT = "";
 
     public ClassSubstitutionVerifier(ProcessingEnvironment env) {
         super(env);
@@ -69,7 +68,7 @@
         assert typeValue != null && stringValue != null && optionalValue != null;
 
         TypeMirror type = resolveAnnotationValue(TypeMirror.class, typeValue);
-        String className = resolveAnnotationValue(String.class, stringValue);
+        String[] classNames = resolveAnnotationValue(String[].class, stringValue);
         boolean optional = resolveAnnotationValue(Boolean.class, optionalValue);
 
         if (type.getKind() != TypeKind.DECLARED) {
@@ -78,7 +77,7 @@
         }
 
         if (!classSubstition.getAnnotationType().asElement().equals(((DeclaredType) type).asElement())) {
-            if (!className.equals(STRING_VALUE_DEFAULT)) {
+            if (classNames.length != 0) {
                 String msg = "The usage of value and className is exclusive.";
                 env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, stringValue);
                 env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, typeValue);
@@ -87,11 +86,15 @@
             return (TypeElement) ((DeclaredType) type).asElement();
         }
 
-        if (!className.equals(STRING_VALUE_DEFAULT)) {
-            TypeElement typeElement = env.getElementUtils().getTypeElement(className);
-            if (typeElement == null && !optional) {
-                env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+        if (classNames.length != 0) {
+            TypeElement typeElement = null;
+            for (String className : classNames) {
+                typeElement = env.getElementUtils().getTypeElement(className);
+                if (typeElement == null && !optional) {
+                    env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+                }
             }
+
             return typeElement;
         }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java	Sat Jan 31 19:03:33 2015 +0100
@@ -25,7 +25,10 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 
-@ClassSubstitution(className = "org.openjdk.jmh.infra.Blackhole", optional = true)
+/**
+ * Substitutions for both the old and new versions of JMH Blackhole helper classes.
+ */
+@ClassSubstitution(className = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"}, optional = true)
 public class BlackholeSubstitutions {
 
     @SuppressWarnings("unused")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.nodes.*;
+
+@ClassSubstitution(GraalDirectives.class)
+public class GraalDirectivesSubstitutions {
+
+    @MethodSubstitution(forced = true)
+    public static void deoptimize() {
+        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void deoptimizeAndInvalidate() {
+        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static boolean inCompiledCode() {
+        return true;
+    }
+
+    @MacroSubstitution(forced = true, macro = ControlFlowAnchorNode.class)
+    public static native void controlFlowAnchor();
+
+    @MethodSubstitution(forced = true)
+    public static boolean injectBranchProbability(double probability, boolean condition) {
+        return BranchProbabilityNode.probability(probability, condition);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(boolean value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(byte value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(short value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(char value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(int value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(long value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(float value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(double value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static void blackhole(Object value) {
+        BlackholeNode.consume(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static boolean opaque(boolean value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static byte opaque(byte value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static short opaque(short value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static char opaque(char value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static int opaque(int value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static long opaque(long value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static float opaque(float value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static double opaque(double value) {
+        return OpaqueNode.opaque(value);
+    }
+
+    @MethodSubstitution(forced = true)
+    public static <T> T opaque(T value) {
+        return OpaqueNode.opaque(value);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Sat Jan 31 19:03:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.directives.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
@@ -47,6 +48,7 @@
 
     public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         BoxingSubstitutions.registerReplacements(replacements);
+        replacements.registerSubstitutions(GraalDirectives.class, GraalDirectivesSubstitutions.class);
         if (Intrinsify.getValue()) {
             replacements.registerSubstitutions(Arrays.class, ArraysSubstitutions.class);
             replacements.registerSubstitutions(Array.class, ArraySubstitutions.class);
@@ -60,13 +62,18 @@
             replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
             replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class);
             replacements.registerSubstitutions(Edges.class, EdgesSubstitutions.class);
-            if (Options.UseBlackholeSubstitution.getValue()) {
-                replacements.registerSubstitutions(new Type() {
-                    public String getTypeName() {
-                        return "org.openjdk.jmh.infra.Blackhole";
-                    }
-                }, BlackholeSubstitutions.class);
-            }
+        }
+        if (Options.UseBlackholeSubstitution.getValue()) {
+            replacements.registerSubstitutions(new Type() {
+                public String getTypeName() {
+                    return "org.openjdk.jmh.infra.Blackhole";
+                }
+            }, BlackholeSubstitutions.class);
+            replacements.registerSubstitutions(new Type() {
+                public String getTypeName() {
+                    return "org.openjdk.jmh.logic.BlackHole";
+                }
+            }, BlackholeSubstitutions.class);
         }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sat Jan 31 19:03:33 2015 +0100
@@ -162,7 +162,12 @@
         private Executable originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
             Class<?> originalClass = classSubstitution.value();
             if (originalClass == ClassSubstitution.class) {
-                originalClass = resolveClass(classSubstitution.className(), classSubstitution.optional());
+                for (String className : classSubstitution.className()) {
+                    originalClass = resolveClass(className, classSubstitution.optional());
+                    if (originalClass != null) {
+                        break;
+                    }
+                }
                 if (originalClass == null) {
                     // optional class was not found
                     return null;
@@ -334,18 +339,26 @@
         return null;
     }
 
-    private static String getOriginalInternalName(Class<?> substitutions) {
+    private static boolean checkSubstitutionInternalName(Class<?> substitutions, String internalName) {
         ClassSubstitution cs = substitutions.getAnnotation(ClassSubstitution.class);
         assert cs != null : substitutions + " must be annotated by " + ClassSubstitution.class.getSimpleName();
         if (cs.value() == ClassSubstitution.class) {
-            return toInternalName(cs.className());
+            for (String className : cs.className()) {
+                if (toInternalName(className).equals(internalName)) {
+                    return true;
+                }
+            }
+            assert false : internalName + " not found in " + Arrays.toString(cs.className());
+        } else {
+            String originalInternalName = toInternalName(cs.value().getName());
+            assert originalInternalName.equals(internalName) : originalInternalName + " != " + internalName;
         }
-        return toInternalName(cs.value().getName());
+        return true;
     }
 
     public void registerSubstitutions(Type original, Class<?> substitutionClass) {
         String internalName = toInternalName(original.getTypeName());
-        assert getOriginalInternalName(substitutionClass).equals(internalName) : getOriginalInternalName(substitutionClass) + " != " + (internalName);
+        assert checkSubstitutionInternalName(substitutionClass, internalName);
         Class<?>[] classes = internalNameToSubstitutionClasses.get(internalName);
         if (classes == null) {
             classes = new Class<?>[]{substitutionClass};
@@ -592,7 +605,8 @@
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    createGraphBuilder(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(
+                                    graph);
                 }
                 afterParsing(graph);
 
@@ -605,8 +619,9 @@
             return graph;
         }
 
-        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
-            return new GraphBuilderPhase.Instance(metaAccess, graphBuilderConfig, optimisticOpts);
+        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig,
+                        OptimisticOptimizations optimisticOpts) {
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
         }
 
         protected void afterParsing(StructuredGraph graph) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java	Sat Jan 31 19:03:33 2015 +0100
@@ -43,47 +43,29 @@
     }
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(boolean v) {
-    }
+    public static native void consume(boolean v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(byte v) {
-    }
+    public static native void consume(byte v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(short v) {
-    }
+    public static native void consume(short v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(char v) {
-    }
+    public static native void consume(char v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(int v) {
-    }
+    public static native void consume(int v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(long v) {
-    }
+    public static native void consume(long v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(float v) {
-    }
+    public static native void consume(float v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(double v) {
-    }
+    public static native void consume(double v);
 
     @NodeIntrinsic
-    @SuppressWarnings("unused")
-    public static void consume(Object v) {
-    }
+    public static native void consume(Object v);
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Sat Jan 31 19:03:33 2015 +0100
@@ -25,12 +25,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 
-/**
- * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a
- * {@link MemoryCheckpoint}.
- */
 @NodeInfo
 public class MathPowNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/OpaqueNode.java	Sat Jan 31 19:03:33 2015 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo
+public class OpaqueNode extends FloatingNode implements LIRLowerable {
+
+    @Input ValueNode value;
+
+    public OpaqueNode(ValueNode value) {
+        super(value.stamp().unrestricted());
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.operand(value));
+    }
+
+    @NodeIntrinsic
+    public static native boolean opaque(boolean v);
+
+    @NodeIntrinsic
+    public static native byte opaque(byte v);
+
+    @NodeIntrinsic
+    public static native short opaque(short v);
+
+    @NodeIntrinsic
+    public static native char opaque(char v);
+
+    @NodeIntrinsic
+    public static native int opaque(int v);
+
+    @NodeIntrinsic
+    public static native long opaque(long v);
+
+    @NodeIntrinsic
+    public static native float opaque(float v);
+
+    @NodeIntrinsic
+    public static native double opaque(double v);
+
+    @NodeIntrinsic
+    public static native <T> T opaque(T v);
+}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Sat Jan 31 19:03:33 2015 +0100
@@ -177,12 +177,12 @@
         Suites suites = suitesProvider.createSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod);
-        new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         CompilationResultBuilderFactory factory = getOptimizedCallTargetInstrumentationFactory(backend.getTarget().arch.getName(), javaMethod);
-        return compileGraph(graph, null, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null,
+        return compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null,
                         suites, new CompilationResult(), factory);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Sat Jan 31 19:03:33 2015 +0100
@@ -94,13 +94,13 @@
 
     public StructuredGraph createInlineGraph(String name) {
         StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), config, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), config, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
 
     public StructuredGraph createRootGraph(String name) {
         StructuredGraph graph = new StructuredGraph(name, callRootMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
 
@@ -294,7 +294,7 @@
 
     protected StructuredGraph parseGraph(final ResolvedJavaMethod method, final PhaseContext phaseContext) {
         final StructuredGraph graph = new StructuredGraph(method);
-        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph);
+        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), config, optimisticOptimizations).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Sat Jan 31 19:03:33 2015 +0100
@@ -153,7 +153,7 @@
             CodeCacheProvider codeCache = providers.getCodeCache();
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
-            result = compileGraph(graph, null, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog,
+            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog,
                             suites, compilationResult, CompilationResultBuilderFactory.Default);
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Sat Jan 31 19:03:33 2015 +0100
@@ -664,7 +664,7 @@
      * Marks a method that it is considered as a boundary for Truffle partial evaluation.
      */
     @Retention(RetentionPolicy.RUNTIME)
-    @Target({ElementType.METHOD})
+    @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
     public @interface TruffleBoundary {
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleTool.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleTool.java	Sat Jan 31 19:03:33 2015 +0100
@@ -66,16 +66,23 @@
 public abstract class TruffleTool {
 
     private enum ToolState {
+
+        /** Not yet installed, inert. */
         UNINSTALLED,
-        ENABLED_INSTALLED,
-        DISABLED_INSTALLED,
+
+        /** Installed, collecting data. */
+        ENABLED,
+
+        /** Installed, not collecting data. */
+        DISABLED,
+
+        /** Was installed, but now removed, inactive, and no longer usable. */
         DISPOSED;
     }
 
     private ToolState toolState = ToolState.UNINSTALLED;
 
     protected TruffleTool() {
-
     }
 
     /**
@@ -85,11 +92,9 @@
      * @throws IllegalStateException if the tool has previously been installed.
      */
     public final void install() {
-        if (toolState != ToolState.UNINSTALLED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has already been installed");
-        }
+        checkUninstalled();
         if (internalInstall()) {
-            toolState = ToolState.ENABLED_INSTALLED;
+            toolState = ToolState.ENABLED;
         }
     }
 
@@ -97,7 +102,7 @@
      * @return whether the tool is currently collecting data.
      */
     public final boolean isEnabled() {
-        return toolState == ToolState.ENABLED_INSTALLED;
+        return toolState == ToolState.ENABLED;
     }
 
     /**
@@ -107,14 +112,9 @@
      * @throws IllegalStateException if not yet installed or disposed.
      */
     public final void setEnabled(boolean isEnabled) {
-        if (toolState == ToolState.UNINSTALLED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed");
-        }
-        if (toolState == ToolState.DISPOSED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed");
-        }
+        checkInstalled();
         internalSetEnabled(isEnabled);
-        toolState = isEnabled ? ToolState.ENABLED_INSTALLED : ToolState.DISABLED_INSTALLED;
+        toolState = isEnabled ? ToolState.ENABLED : ToolState.DISABLED;
     }
 
     /**
@@ -123,12 +123,7 @@
      * @throws IllegalStateException if not yet installed or disposed.
      */
     public final void reset() {
-        if (toolState == ToolState.UNINSTALLED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed");
-        }
-        if (toolState == ToolState.DISPOSED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed");
-        }
+        checkInstalled();
         internalReset();
     }
 
@@ -139,12 +134,7 @@
      * @throws IllegalStateException if not yet installed or disposed.
      */
     public final void dispose() {
-        if (toolState == ToolState.UNINSTALLED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed");
-        }
-        if (toolState == ToolState.DISPOSED) {
-            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed");
-        }
+        checkInstalled();
         internalDispose();
         toolState = ToolState.DISPOSED;
     }
@@ -156,7 +146,7 @@
 
     /**
      * No subclass action required.
-     * 
+     *
      * @param isEnabled
      */
     protected void internalSetEnabled(boolean isEnabled) {
@@ -166,4 +156,29 @@
 
     protected abstract void internalDispose();
 
+    /**
+     * Ensure that the tool is currently installed.
+     *
+     * @throws IllegalStateException
+     */
+    private void checkInstalled() throws IllegalStateException {
+        if (toolState == ToolState.UNINSTALLED) {
+            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " not yet installed");
+        }
+        if (toolState == ToolState.DISPOSED) {
+            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has been disposed");
+        }
+    }
+
+    /**
+     * Ensure that the tool has not yet been installed.
+     *
+     * @throws IllegalStateException
+     */
+    private void checkUninstalled() {
+        if (toolState != ToolState.UNINSTALLED) {
+            throw new IllegalStateException("Tool " + getClass().getSimpleName() + " has already been installed");
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Sat Jan 31 19:03:33 2015 +0100
@@ -437,6 +437,9 @@
      * that intercepts execution events at the node and routes them to any {@link Instrument}s that
      * have been attached to the {@link Probe}. Only one {@link Probe} may be installed at each
      * node; subsequent calls return the one already installed.
+     * <p>
+     * <b>Note:</b> instrumentation requires a appropriate {@link WrapperNode}, which must be
+     * provided by {@link #createWrapperNode()}.
      *
      * @see Instrument
      */
@@ -449,7 +452,7 @@
      * <ol>
      * <li>implements {@link WrapperNode}</li>
      * <li>has {@code this} as it's child, and</li>
-     * <li>whose type is suitable for (unsafe) replacement of {@code this} in the parent.</li>
+     * <li>whose type is safe for replacement of {@code this} in the parent.</li>
      * </ol>
      *
      * @return an appropriately typed {@link WrapperNode} if {@link #isInstrumentable()}.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Sat Jan 31 19:03:33 2015 +0100
@@ -362,15 +362,6 @@
             return childrenFields;
         }
 
-        public NodeField findField(long fieldOffset) {
-            for (NodeField field : getFields()) {
-                if (field.getOffset() == fieldOffset) {
-                    return field;
-                }
-            }
-            return null;
-        }
-
         @Override
         public int hashCode() {
             return clazz.hashCode();
@@ -665,20 +656,18 @@
         NodeClass parentNodeClass = NodeClass.get(parent.getClass());
 
         for (NodeField field : parentNodeClass.getChildFields()) {
-            final long fieldOffset = field.getOffset();
-            if (unsafe.getObject(parent, fieldOffset) == child) {
-                return parentNodeClass.findField(fieldOffset);
+            if (field.getObject(parent) == child) {
+                return field;
             }
         }
 
         for (NodeField field : parentNodeClass.getChildrenFields()) {
-            final long fieldOffset = field.getOffset();
-            Object arrayObject = unsafe.getObject(parent, fieldOffset);
+            Object arrayObject = field.getObject(parent);
             if (arrayObject != null) {
                 Object[] array = (Object[]) arrayObject;
                 for (int i = 0; i < array.length; i++) {
                     if (array[i] == child) {
-                        return parentNodeClass.findField(fieldOffset);
+                        return field;
                     }
                 }
             }
@@ -1091,6 +1080,7 @@
             final StringBuilder sb = new StringBuilder();
             sb.append("source:");
             sb.append(" (" + section.getCharIndex() + "," + (section.getCharEndIndex() - 1) + ")");
+            sb.append(" line=" + section.getLineLocation().getLineNumber());
             sb.append(" len=" + srcText.length());
             sb.append(" text=\"" + srcText + "\"");
             return sb.toString();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Sat Jan 31 19:03:33 2015 +0100
@@ -96,8 +96,12 @@
      */
     private final TruffleEventReceiver eventReceiver = new DefaultEventReceiver() {
         @Override
+        public void enter(Node node, VirtualFrame frame) {
+            internalReceive(node);
+        }
+
         @TruffleBoundary
-        public void enter(Node node, VirtualFrame frame) {
+        private void internalReceive(Node node) {
             if (isEnabled()) {
                 final Class<?> nodeClass = node.getClass();
                 AtomicLong nodeCounter = counters.get(nodeClass);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java	Wed Jan 28 15:07:54 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java	Sat Jan 31 19:03:33 2015 +0100
@@ -44,36 +44,22 @@
      */
     public boolean visit(Node node) {
 
-        if (node.isInstrumentable()) {
-
-            if (node instanceof SLStatementNode) {
-
-                // Distinguish between SLExpressionNode and SLStatementNode since some of the
-                // generated factory methods that require SLExpressionNodes as parameters.
-                // Since
-                // SLExpressionNodes are a subclass of SLStatementNode, check if something is an
-                // SLExpressionNode first.
-                if (node instanceof SLExpressionNode && node.getParent() != null) {
-                    SLExpressionNode expressionNode = (SLExpressionNode) node;
-                    if (expressionNode.getSourceSection() != null) {
-                        Probe probe = expressionNode.probe();
+        if (node instanceof SLStatementNode && node.getParent() != null && node.getSourceSection() != null) {
+            // All SL nodes are instrumentable, but treat expressions specially
 
-                        if (node instanceof SLWriteLocalVariableNode) {
-                            probe.tagAs(STATEMENT, null);
-                            probe.tagAs(ASSIGNMENT, null);
-                        }
-                    }
-                } else if (node instanceof SLStatementNode && node.getParent() != null) {
-
-                    SLStatementNode statementNode = (SLStatementNode) node;
-                    if (statementNode.getSourceSection() != null) {
-                        Probe probe = statementNode.probe();
-                        probe.tagAs(STATEMENT, null);
-
-                        if (node instanceof SLWhileNode) {
-                            probe.tagAs(START_LOOP, null);
-                        }
-                    }
+            if (node instanceof SLExpressionNode) {
+                SLExpressionNode expressionNode = (SLExpressionNode) node;
+                Probe probe = expressionNode.probe();
+                if (node instanceof SLWriteLocalVariableNode) {
+                    probe.tagAs(STATEMENT, null);
+                    probe.tagAs(ASSIGNMENT, null);
+                }
+            } else {
+                SLStatementNode statementNode = (SLStatementNode) node;
+                Probe probe = statementNode.probe();
+                probe.tagAs(STATEMENT, null);
+                if (node instanceof SLWhileNode) {
+                    probe.tagAs(START_LOOP, null);
                 }
             }
         }
--- a/mx/mx_graal.py	Wed Jan 28 15:07:54 2015 +0100
+++ b/mx/mx_graal.py	Sat Jan 31 19:03:33 2015 +0100
@@ -1360,7 +1360,7 @@
     if not containsF:
         jmhArgs += ['-f1']
 
-    # find all projects with the JMH dependency
+    # find all projects with a direct JMH dependency
     jmhProjects = []
     for p in mx.projects():
         if 'JMH' in p.deps:
--- a/mx/suite.py	Wed Jan 28 15:07:54 2015 +0100
+++ b/mx/suite.py	Sat Jan 31 19:03:33 2015 +0100
@@ -220,6 +220,25 @@
       "workingSets" : "API,Graal",
     },
 
+    "com.oracle.graal.api.directives" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "com.oracle.graal.api.directives.test" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "com.oracle.graal.graph",
+      "dependencies" : [
+        "com.oracle.graal.compiler.test",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
     "com.oracle.graal.api.runtime" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -582,6 +601,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.compiler",
         "com.oracle.graal.java",
         "com.oracle.graal.word",
@@ -798,6 +818,7 @@
         "com.oracle.graal.phases",
       ],
       "checkstyle" : "com.oracle.graal.graph",
+      "annotationProcessors" : ["com.oracle.graal.service.processor"],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Java",
     },
@@ -854,6 +875,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.test",
         "com.oracle.graal.printer",
         "com.oracle.graal.runtime",
--- a/src/share/vm/graal/graalRuntime.cpp	Wed Jan 28 15:07:54 2015 +0100
+++ b/src/share/vm/graal/graalRuntime.cpp	Sat Jan 31 19:03:33 2015 +0100
@@ -38,7 +38,6 @@
 #include "runtime/reflection.hpp"
 #include "utilities/debug.hpp"
 
-address GraalRuntime::_external_deopt_i2c_entry = NULL;
 jobject GraalRuntime::_HotSpotGraalRuntime_instance = NULL;
 bool GraalRuntime::_HotSpotGraalRuntime_initialized = false;
 bool GraalRuntime::_shutdown_called = false;
@@ -60,13 +59,6 @@
 
     graal_compute_offsets();
 
-#ifdef TARGET_ARCH_x86
-#ifdef _LP64
-    // Only supported on x86_64 for now
-    _external_deopt_i2c_entry = create_external_deopt_i2c();
-#endif
-#endif
-
     // Ensure _non_oop_bits is initialized
     Universe::non_oop_word();
 
@@ -89,39 +81,6 @@
   return buffer_blob;
 }
 
-address GraalRuntime::create_external_deopt_i2c() {
-  ResourceMark rm;
-  BufferBlob* buffer = BufferBlob::create("externalDeopt", 1*K);
-  CodeBuffer cb(buffer);
-  short buffer_locs[20];
-  cb.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo));
-  MacroAssembler masm(&cb);
-
-  int total_args_passed = 6;
-
-  BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
-  VMRegPair* regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
-  int i = 0;
-  sig_bt[i++] = T_INT;
-  sig_bt[i++] = T_LONG;
-  sig_bt[i++] = T_VOID; // long stakes 2 slots
-  sig_bt[i++] = T_INT;
-  sig_bt[i++] = T_OBJECT;
-  sig_bt[i++] = T_INT; // The number of actual arguments passed to the method.
-
-  int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
-
-  SharedRuntime::gen_i2c_adapter(&masm, total_args_passed, comp_args_on_stack, sig_bt, regs, total_args_passed - 1);
-  masm.flush();
-
-  AdapterBlob* adapter = AdapterBlob::create(&cb);
-  if (PrintAdapterHandlers) {
-    tty->print_cr("Decoding external_deopt_i2c");
-    Disassembler::decode(adapter->code_begin(), adapter->code_end());
-  }
-  return adapter->code_begin();
-}
-
 BasicType GraalRuntime::kindToBasicType(jchar ch) {
   switch(ch) {
     case 'z': return T_BOOLEAN;
--- a/src/share/vm/graal/graalRuntime.hpp	Wed Jan 28 15:07:54 2015 +0100
+++ b/src/share/vm/graal/graalRuntime.hpp	Sat Jan 31 19:03:33 2015 +0100
@@ -33,7 +33,6 @@
 
   static jobject _HotSpotGraalRuntime_instance;
   static bool _HotSpotGraalRuntime_initialized;
-  static address _external_deopt_i2c_entry;
   static const char* _generated_sources_sha1;
 
   static bool _shutdown_called;
@@ -222,11 +221,6 @@
   static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
 
   static BasicType kindToBasicType(jchar ch);
-  static address create_external_deopt_i2c();
-  static address get_external_deopt_i2c_entry() {
-    guarantee(_external_deopt_i2c_entry != NULL, "unsupported");
-    return _external_deopt_i2c_entry;
-  }
 
   // The following routines are all called from compiled Graal code