changeset 19092:5e33637f5e5a

Merge StackSlotAllocation cleanups.
author Josef Eisl <josef.eisl@jku.at>
date Tue, 03 Feb 2015 11:10:24 +0100
parents 336adcd0070b (diff) 684612ee6abb (current diff)
children 81e464d45137 08eacfeb8b76
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java
diffstat 78 files changed, 2496 insertions(+), 622 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Sat Jan 31 15:51:54 2015 +0100
+++ b/CHANGELOG.md	Tue Feb 03 11:10:24 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
--- /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	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 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.runtime/src/com/oracle/graal/api/runtime/Services.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java	Tue Feb 03 11:10:24 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/BaselineCompiler.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Tue Feb 03 11:10:24 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.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Tue Feb 03 11:10:24 2015 +0100
@@ -317,6 +317,49 @@
         return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(","));
     }
 
+    private boolean opsEquals(ArithmeticOpTable that) {
+        // @formatter:off
+        return Objects.equals(neg, that.neg) &&
+               Objects.equals(add, that.add) &&
+               Objects.equals(sub, that.sub) &&
+               Objects.equals(mul, that.mul) &&
+               Objects.equals(div, that.div) &&
+               Objects.equals(rem, that.rem) &&
+               Objects.equals(not, that.not) &&
+               Objects.equals(and, that.and) &&
+               Objects.equals(or, that.or) &&
+               Objects.equals(xor, that.xor) &&
+               Objects.equals(shl, that.shl) &&
+               Objects.equals(shr, that.shr) &&
+               Objects.equals(ushr, that.ushr) &&
+               Objects.equals(abs, that.abs) &&
+               Objects.equals(sqrt, that.sqrt) &&
+               Objects.equals(zeroExtend, that.zeroExtend) &&
+               Objects.equals(signExtend, that.signExtend) &&
+               Objects.equals(narrow, that.narrow);
+        // @formatter:on
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ArithmeticOpTable that = (ArithmeticOpTable) obj;
+        if (opsEquals(that)) {
+            if (Arrays.equals(this.floatConvert, that.floatConvert)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public String toString() {
         return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" +
@@ -337,19 +380,26 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
-            if (obj == this) {
-                return true;
-            }
-            if (obj != null && getClass() == obj.getClass()) {
-                return obj.toString().equals(toString());
-            }
-            return false;
+        public int hashCode() {
+            return operator.hashCode();
         }
 
         @Override
-        public int hashCode() {
-            return toString().hashCode();
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            Op that = (Op) obj;
+            if (operator.equals(that.operator)) {
+                return true;
+            }
+            return true;
         }
     }
 
@@ -533,6 +583,36 @@
         }
 
         @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + (associative ? 1231 : 1237);
+            result = prime * result + (commutative ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            BinaryOp<?> that = (BinaryOp<?>) obj;
+            if (associative != that.associative) {
+                return false;
+            }
+            if (commutative != that.commutative) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
         public String toString() {
             if (associative) {
                 if (commutative) {
@@ -611,6 +691,30 @@
         public FloatConvertOp unwrap() {
             return this;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            return prime * super.hashCode() + op.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            FloatConvertOp that = (FloatConvertOp) obj;
+            if (op != that.op) {
+                return false;
+            }
+            return true;
+        }
     }
 
     public abstract static class IntegerConvertOp<T> extends Op {
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticStamp.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticStamp.java	Tue Feb 03 11:10:24 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.common.type;
 
 import java.nio.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 
@@ -59,7 +60,7 @@
         if (!(obj instanceof ArithmeticStamp)) {
             return false;
         }
-        assert this.ops.toString().equals(((ArithmeticStamp) obj).ops.toString());
+        assert Objects.equals(ops, ((ArithmeticStamp) obj).ops);
         return true;
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Tue Feb 03 11:10:24 2015 +0100
@@ -256,9 +256,6 @@
         if (!(otherStamp instanceof IntegerStamp)) {
             return StampFactory.illegal(Kind.Illegal);
         }
-        if (equals(otherStamp)) {
-            return this;
-        }
         IntegerStamp other = (IntegerStamp) otherStamp;
         return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Tue Feb 03 11:10:24 2015 +0100
@@ -325,7 +325,7 @@
         canonicalizer.apply(graph, context);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         if (loopPeeling) {
-            new LoopTransformHighPhase().apply(graph);
+            new LoopPeelingPhase().apply(graph);
         }
         new DeadCodeEliminationPhase().apply(graph);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTestSubstitutions.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Feb 03 11:10:24 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/LoopUnswitchTest.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Feb 03 11:10:24 2015 +0100
@@ -124,7 +124,7 @@
         final StructuredGraph graph = parseEager(snippet);
         final StructuredGraph referenceGraph = parseEager(referenceSnippet);
 
-        new LoopTransformLowPhase().apply(graph);
+        new LoopUnswitchingPhase().apply(graph);
 
         // Framestates create comparison problems
         for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Tue Feb 03 11:10:24 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);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Tue Feb 03 11:10:24 2015 +0100
@@ -339,8 +339,7 @@
     @Test
     public void testPeeledLoop() {
         prepareGraph("testPeeledLoopSnippet", false);
-        new LoopTransformHighPhase().apply(graph);
-        new LoopTransformLowPhase().apply(graph);
+        new LoopPeelingPhase().apply(graph);
         new SchedulePhase().apply(graph);
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java	Tue Feb 03 11:10:24 2015 +0100
@@ -25,6 +25,8 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
 
 /**
  * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at
@@ -38,15 +40,31 @@
 public class GraalTutorial extends InvokeGraal {
 
     /*
+     * Example for the Graal API: access the Graal API metadata object for a method.
+     */
+
+    @Test
+    public void testPrintBytecodes() {
+        ResolvedJavaMethod method = findMethod(String.class, "hashCode");
+
+        byte[] bytecodes = method.getCode();
+        Assert.assertNotNull(bytecodes);
+
+        System.out.println(new BytecodeDisassembler().disassemble(method));
+    }
+
+    /*
      * A simple Graal compilation example: Compile the method String.hashCode()
      */
 
     @Test
     public void testStringHashCode() throws InvalidInstalledCodeException {
+        int expectedResult = "Hello World".hashCode();
+
         InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode"));
 
         int result = (int) installedCode.executeVarargs("Hello World");
-        Assert.assertEquals(-862545276, result);
+        Assert.assertEquals(expectedResult, result);
     }
 
     /*
@@ -70,7 +88,9 @@
         /*
          * Collect profiling information by running the method in the interpreter.
          */
+
         for (int i = 0; i < 10000; i++) {
+            /* Execute several times so that enough profiling information gets collected. */
             speculativeOptimization(false);
         }
 
@@ -121,13 +141,17 @@
 
     @Test
     public void testInstanceOfUsage() throws InvalidInstalledCodeException {
-        A a = new A();
+        /*
+         * Collect profiling information by running the method in the interpreter.
+         */
 
-        /* Allocate an (unsued) instance of B so that the class B gets loaded. */
+        A a = new A();
+        /* Allocate an (unused) instance of B so that the class B gets loaded. */
         @SuppressWarnings("unused")
         B b = new B();
-
+        int expectedResult = instanceOfUsage(a);
         for (int i = 0; i < 10000; i++) {
+            /* Execute several times so that enough profiling information gets collected. */
             instanceOfUsage(a);
         }
 
@@ -136,7 +160,7 @@
         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage"));
 
         int result = (int) compiledMethod.executeVarargs(a);
-        Assert.assertEquals(42, result);
+        Assert.assertEquals(expectedResult, result);
     }
 
     /*
@@ -149,9 +173,11 @@
 
     @Test
     public void testIntrinsicUsage() throws InvalidInstalledCodeException {
+        double expectedResult = intrinsicUsage(42d);
+
         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage"));
 
         double result = (double) compiledMethod.executeVarargs(42d);
-        Assert.assertEquals(Math.sin(42), result, 0);
+        Assert.assertEquals(expectedResult, result, 0);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Tue Feb 03 11:10:24 2015 +0100
@@ -114,11 +114,10 @@
 
             /* Advanced configuration objects that are not mandatory. */
             Map<ResolvedJavaMethod, StructuredGraph> cache = null;
-            Object stub = null;
             SpeculationLog speculationLog = null;
 
             /* Invoke the whole Graal compilation pipeline. */
-            GraalCompiler.compileGraph(graph, stub, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites,
+            GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites,
                             compilationResult, factory);
 
             /*
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Feb 03 11:10:24 2015 +0100
@@ -24,6 +24,7 @@
 
 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.*;
@@ -33,6 +34,7 @@
 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.*;
@@ -57,20 +59,23 @@
 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) {
+    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.
+     * parameters, because the possible types of the parameters would not be known.
      */
     public void addMethod(ResolvedJavaMethod method) {
         if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) {
@@ -217,7 +222,7 @@
                      * the code before static analysis, the classes would otherwise be not loaded
                      * yet and the bytecode parser would only create a graph.
                      */
-                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault().withOmitAllExceptionEdges(true);
+                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault();
                     /*
                      * For simplicity, we ignore all exception handling during the static analysis.
                      * This is a constraint of this example code, a real static analysis needs to
@@ -231,8 +236,9 @@
                      * wrong.
                      */
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
+                    Assumptions assumptions = new Assumptions(false);
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, graphBuilderConfig, optimisticOpts);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     Debug.handle(ex);
@@ -305,7 +311,7 @@
      * The active element for method invocations. For {@link InvokeKind#Virtual virtual} and
      * {@link InvokeKind#Interface interface} calls, the {@link TypeFlow#getTypes() types} of this
      * node are the receiver types. When a new receiver type is added, a new callee might be added.
-     * Adding a new callee means liking the type flow of the actual parameters with the formal
+     * Adding a new callee means linking the type flow of the actual parameters with the formal
      * parameters of the callee, and linking the return value of the callee with the return value
      * state of the invocation.
      *
@@ -313,7 +319,6 @@
      * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for
      * simplicity.
      */
-
     class InvokeTypeFlow extends TypeFlow {
         private final MethodCallTargetNode callTarget;
         private final TypeFlow[] actualParameters;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysisTests.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysisTests.java	Tue Feb 03 11:10:24 2015 +0100
@@ -32,6 +32,7 @@
 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.*;
 
@@ -58,12 +59,14 @@
         Object f;
     }
 
-    private MetaAccessProvider metaAccess;
+    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() {
@@ -73,7 +76,7 @@
 
     @Test
     public void test01() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess);
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry"));
         sa.finish();
 
@@ -94,7 +97,7 @@
 
     @Test
     public void test02() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess);
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry"));
         sa.finish();
 
@@ -121,7 +124,7 @@
 
     @Test
     public void test03() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess);
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry"));
         sa.finish();
 
@@ -151,7 +154,7 @@
 
     @Test
     public void test04() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess);
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry"));
         sa.finish();
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Feb 03 11:10:24 2015 +0100
@@ -132,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;
@@ -152,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
@@ -165,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;
@@ -204,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));
     }
 
     /**
@@ -221,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);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java	Tue Feb 03 11:10:24 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.phases;
 
-import static com.oracle.graal.graph.Graph.NodeEvent.*;
-
 import java.util.stream.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.Graph.NodeEvent;
 import com.oracle.graal.graph.Graph.NodeEventScope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -60,9 +59,13 @@
 
     @Override
     protected void run(StructuredGraph graph, C context) {
-        HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(INPUT_CHANGED);
-        try (NodeEventScope s = graph.trackNodeEvents(listener)) {
-            StructuredGraph graphCopy = graph.copy();
+        /*
+         * Phase may add nodes but not end up using them so ignore additions. Nodes going dead and
+         * having their inputs change are the main interesting differences.
+         */
+        HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NodeEvent.NODE_ADDED);
+        StructuredGraph graphCopy = graph.copy();
+        try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) {
             try (Scope s2 = Debug.sandbox("WithoutMonitoring", null)) {
                 super.run(graphCopy, context);
             } catch (Throwable t) {
@@ -70,10 +73,10 @@
             }
         }
         if (!listener.getNodes().isEmpty()) {
-            // rerun it on the real graph in a new Debug scope so Dump and Log can find it.
-            listener = new HashSetNodeEventListener().exclude(INPUT_CHANGED);
+            /* rerun it on the real graph in a new Debug scope so Dump and Log can find it. */
+            listener = new HashSetNodeEventListener();
             try (NodeEventScope s = graph.trackNodeEvents(listener)) {
-                try (Scope s2 = Debug.scope("GraphChangeMonitoring." + getName() + "-" + message)) {
+                try (Scope s2 = Debug.scope("WithGraphChangeMonitoring." + getName() + "-" + message)) {
                     if (Debug.isDumpEnabled(BasePhase.PHASE_DUMP_LEVEL)) {
                         Debug.dump(BasePhase.PHASE_DUMP_LEVEL, graph, "*** Before phase %s", getName());
                     }
@@ -81,8 +84,8 @@
                     if (Debug.isDumpEnabled(BasePhase.PHASE_DUMP_LEVEL)) {
                         Debug.dump(BasePhase.PHASE_DUMP_LEVEL, graph, "*** After phase %s", getName());
                     }
+                    Debug.log("*** %s %s %s\n", message, graph, listener.getNodes().stream().filter(e -> !e.isAlive()).collect(Collectors.toSet()));
                 }
-                Debug.log("*** %s %s %s\n", message, graph, listener.getNodes().stream().filter(e -> !e.isAlive()).collect(Collectors.toSet()));
             }
         } else {
             // Go ahead and run it normally even though it should have no effect
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Feb 03 11:10:24 2015 +0100
@@ -85,8 +85,12 @@
         }
 
         if (OptLoopTransform.getValue()) {
-            appendPhase(new LoopTransformHighPhase());
-            appendPhase(new LoopTransformLowPhase());
+            if (LoopPeeling.getValue()) {
+                appendPhase(new LoopPeelingPhase());
+            }
+            if (LoopUnswitch.getValue()) {
+                appendPhase(new LoopUnswitchingPhase());
+            }
         }
         appendPhase(new RemoveValueProxyPhase());
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Feb 03 11:10:24 2015 +0100
@@ -89,6 +89,10 @@
 
         appendPhase(new FrameStateAssignmentPhase());
 
+        if (ReassociateInvariants.getValue()) {
+            appendPhase(new ReassociateInvariantPhase());
+        }
+
         if (OptDeoptimizationGrouping.getValue()) {
             appendPhase(new DeoptimizationGroupingPhase());
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Tue Feb 03 11:10:24 2015 +0100
@@ -331,7 +331,13 @@
             } else {
                 subIndex++;
             }
-            while (index < edges.getCount()) {
+            if (index < edges.getCount()) {
+                forwardNodeList();
+            }
+        }
+
+        private void forwardNodeList() {
+            do {
                 if (subIndex == 0) {
                     list = edges.getNodeList(node, index);
                 }
@@ -346,7 +352,7 @@
                 }
                 subIndex = 0;
                 index++;
-            }
+            } while (index < edges.getCount());
         }
 
         private Node nextElement() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Feb 03 11:10:24 2015 +0100
@@ -166,7 +166,7 @@
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
-        startGVNNumber = clazz.getName().hashCode();
+        startGVNNumber = clazz.hashCode();
 
         NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class);
         assert info != null : "Missing NodeInfo annotation on " + clazz;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue Feb 03 11:10:24 2015 +0100
@@ -98,6 +98,14 @@
         values[getNodeId(node)] = value;
     }
 
+    /**
+     * @param i
+     * @return Return the key for the entry at index {@code i}
+     */
+    protected Node getKey(int i) {
+        return graph.getNode(i);
+    }
+
     public int size() {
         return values.length;
     }
@@ -135,7 +143,7 @@
                     @Override
                     public Entry<Node, T> next() {
                         final int pos = i;
-                        Node key = NodeMap.this.graph.getNode(pos);
+                        Node key = NodeMap.this.getKey(pos);
                         T value = (T) NodeMap.this.values[pos];
                         i++;
                         forward();
@@ -158,7 +166,7 @@
                     }
 
                     private void forward() {
-                        while (i < NodeMap.this.values.length && (NodeMap.this.graph.getNode(i) == null || NodeMap.this.values[i] == null)) {
+                        while (i < NodeMap.this.values.length && (NodeMap.this.getKey(i) == null || NodeMap.this.values[i] == null)) {
                             i++;
                         }
                     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Tue Feb 03 11:10:24 2015 +0100
@@ -56,10 +56,21 @@
 
     public Set<Node> keySet() {
         HashSet<Node> entries = new HashSet<>();
-        for (Map.Entry<Node, Node> entry : entries()) {
-            entries.add(entry.getKey());
+        for (int i = 0; i < values.length; ++i) {
+            Object v = values[i];
+            if (v != null) {
+                Node key = getKey(i);
+                if (key != null) {
+                    entries.add(key);
+                }
+            }
         }
-        return entries;
+        /*
+         * The normal contract for entrySet is that modifications of the set are reflected in the
+         * underlying data structure. For simplicity don't allow that but complain if someone tries
+         * to use it that way.
+         */
+        return Collections.unmodifiableSet(entries);
     }
 
     public Collection<Node> values() {
@@ -78,6 +89,11 @@
         for (Map.Entry<Node, Node> entry : entries()) {
             entries.add(entry);
         }
-        return entries;
+        /*
+         * The normal contract for entrySet is that modifications of the set are reflected in the
+         * underlying data structure. For simplicity don't allow that but complain if someone tries
+         * to use it that way.
+         */
+        return Collections.unmodifiableSet(entries);
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Feb 03 11:10:24 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/HotSpotGraalRuntime.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Feb 03 11:10:24 2015 +0100
@@ -91,6 +91,7 @@
      * Do deferred initialization.
      */
     public void completeInitialization() {
+        TTY.initialize(Options.LogFile.getStream(compilerToVm));
 
         // Proxies for the VM/Compiler interfaces cannot be initialized
         // in the constructor as proxy creation causes static
@@ -109,8 +110,6 @@
 
         this.compilerToVm = toVM;
 
-        TTY.initialize(Options.LogFile.getStream(compilerToVm));
-
         if (Log.getValue() == null && Meter.getValue() == null && Time.getValue() == null && Dump.getValue() == null && Verify.getValue() == null) {
             if (MethodFilter.getValue() != null) {
                 TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, Dump and Verify options are all null");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Feb 03 11:10:24 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/logging/CountingProxy.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java	Tue Feb 03 11:10:24 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.logging;
 
-import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
@@ -97,13 +96,12 @@
 
     protected void print() {
         long sum = 0;
-        PrintStream out = System.out;
         for (Map.Entry<Method, AtomicLong> entry : calls.entrySet()) {
             Method method = entry.getKey();
             long count = entry.getValue().get();
             sum += count;
-            out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count);
+            TTY.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count);
         }
-        out.println(delegate.getClass().getSimpleName() + " calls: " + sum);
+        TTY.println(delegate.getClass().getSimpleName() + " calls: " + sum);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Feb 03 11:10:24 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.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Feb 03 11:10:24 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())) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Tue Feb 03 11:10:24 2015 +0100
@@ -105,7 +105,7 @@
                     if (superKlass.equal(0)) {
                         return null;
                     } else {
-                        return piCastExactNonNull(superKlass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION), Class.class);
+                        return readJavaMirror(superKlass);
                     }
                 }
             }
@@ -113,6 +113,10 @@
         return null;
     }
 
+    public static Class<?> readJavaMirror(Word klass) {
+        return piCastExactNonNull(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION), Class.class);
+    }
+
     @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getComponentType(final Class<?> thisObj) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompilerToVMImplSubstitutions.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.replacements;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@link CompilerToVMImpl} methods.
+ */
+@ClassSubstitution(com.oracle.graal.hotspot.bridge.CompilerToVMImpl.class)
+public class CompilerToVMImplSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getJavaMirror(@SuppressWarnings("unused") CompilerToVMImpl impl, long metaspaceklass) {
+        return ClassSubstitutions.readJavaMirror(Word.unsigned(metaspaceklass));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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.*;
+
+/**
+ * Provider of HotSpot specific {@link GraphBuilderPlugin}s.
+ */
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        plugins.register(metaAccess, ObjectPlugin.class);
+    }
+
+    /**
+     * HotSpot specific plugins for {@link Object}.
+     */
+    enum ObjectPlugin implements GraphBuilderPlugin {
+        getClass() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                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());
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Feb 03 11:10:24 2015 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
@@ -65,6 +66,7 @@
         replacements.registerSubstitutions(NodeClass.class, HotSpotNodeClassSubstitutions.class);
         replacements.registerSubstitutions(Node.class, HotSpotNodeSubstitutions.class);
         replacements.registerSubstitutions(CompositeValueClass.class, CompositeValueClassSubstitutions.class);
+        replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
         replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
         replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class);
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
+ */
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        plugins.register(metaAccess, ObjectPlugin.class);
+        plugins.register(metaAccess, BoxingPlugin.class);
+    }
+
+    /**
+     * Plugins for {@link Object}.
+     */
+    enum ObjectPlugin implements GraphBuilderPlugin {
+        init() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                ValueNode object = args[0];
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
+                }
+                return true;
+            }
+
+            public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
+                return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, "<init>");
+            }
+        };
+
+        @Override
+        public String toString() {
+            return Object.class.getName() + "." + name() + "()";
+        }
+    }
+
+    /**
+     * Plugins for the standard primitive box classes (e.g., {@link Integer} and friends).
+     */
+    enum BoxingPlugin implements GraphBuilderPlugin {
+        valueOf$Boolean(Kind.Boolean),
+        booleanValue$Boolean(Kind.Boolean),
+        valueOf$Byte(Kind.Byte),
+        byteValue$Byte(Kind.Byte),
+        valueOf$Short(Kind.Short),
+        shortValue$Short(Kind.Short),
+        valueOf$Char(Kind.Char),
+        charValue$Char(Kind.Char),
+        valueOf$Int(Kind.Int),
+        intValue$Int(Kind.Int),
+        valueOf$Long(Kind.Long),
+        longValue$Long(Kind.Long),
+        valueOf$Float(Kind.Float),
+        floatValue$Float(Kind.Float),
+        valueOf$Double(Kind.Double),
+        doubleValue$Double(Kind.Double);
+
+        BoxingPlugin(Kind kind) {
+            assert name().startsWith("valueOf$") || name().startsWith(kind.getJavaName() + "Value$");
+            this.kind = kind;
+            this.box = name().charAt(0) == 'v';
+        }
+
+        private final Kind kind;
+        private final boolean box;
+
+        public final boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+            if (box) {
+                ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+                builder.push(Kind.Object, builder.append(new BoxNode(args[0], resultType, kind)));
+            } else {
+                builder.push(kind, builder.append(new UnboxNode(args[0], kind)));
+            }
+            return true;
+        }
+
+        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
+            Class<?>[] parameterTypes = box ? new Class<?>[]{kind.toJavaClass()} : new Class<?>[0];
+            return GraphBuilderPlugin.resolveTarget(metaAccess, kind.toBoxedJavaClass(), name(), parameterTypes);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Feb 03 11:10:24 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,53 @@
                         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());
+                    if (graphBuilderPlugins != null) {
+                        GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod);
+                        if (plugin != null) {
+                            int beforeStackSize = frameState.stackSize;
+                            if (plugin.handleInvocation(this, args)) {
+                                // System.out.println("used plugin: " + plugin);
+                                assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize;
+                                return;
                             }
-                            return lazyFrameState[0];
-                        });
-                        startFrameState.initializeFromArgumentsArray(args);
-                        parser.build(currentDepth + 1, this.lastInstr, startFrameState);
+                            assert beforeStackSize == frameState.stackSize;
+                        }
+                    }
 
-                        FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
-                        this.lastInstr = calleeBeforeReturnNode;
-                        if (calleeBeforeReturnNode != null) {
-                            ValueNode calleeReturnValue = parser.getReturnValue();
-                            if (calleeReturnValue != null) {
-                                frameState.push(calleeReturnValue.getKind().getStackKind(), calleeReturnValue);
-                            }
-                        }
+                    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 calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
-                        if (calleeBeforeUnwindNode != null) {
-                            ValueNode calleeUnwindValue = parser.getUnwindValue();
-                            assert calleeUnwindValue != null;
-                            calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+                            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 +970,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 +979,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 +988,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 +997,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 +1489,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	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,64 @@
+/*
+ * 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 method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} .
+     */
+    ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess);
+
+    /**
+     * Looks up a {@link ResolvedJavaMethod}.
+     *
+     * @param methodNameBase the name of the method is the prefix of this value up to the first '$'
+     *            character
+     */
+    static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class<?> declaringClass, String methodNameBase, Class<?>... parameterTypes) {
+        int index = methodNameBase.indexOf('$');
+        String methodName = index == -1 ? methodNameBase : methodNameBase.substring(0, index);
+        try {
+            return metaAccess.lookupJavaMethod(methodName.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes));
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * 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);
+            // System.out.println("registered: " + 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	Tue Feb 03 11:10:24 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/src/com/oracle/graal/lir/LIRInsertionBuffer.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInsertionBuffer.java	Tue Feb 03 11:10:24 2015 +0100
@@ -48,7 +48,8 @@
      * index into lir list where "count" ops should be inserted indexAndCount[i * 2 + 1]: the number
      * of ops to be inserted at index
      */
-    private final List<Integer> indexAndCount;
+    private int[] indexAndCount;
+    private int indexAndCountSize;
 
     /**
      * The LIROps to be inserted.
@@ -56,8 +57,8 @@
     private final List<LIRInstruction> ops;
 
     public LIRInsertionBuffer() {
-        indexAndCount = new ArrayList<>(8);
-        ops = new ArrayList<>(8);
+        indexAndCount = new int[8];
+        ops = new ArrayList<>(4);
     }
 
     /**
@@ -65,7 +66,7 @@
      */
     public void init(List<LIRInstruction> newLir) {
         assert !initialized() : "already initialized";
-        assert indexAndCount.size() == 0 && ops.size() == 0;
+        assert indexAndCountSize == 0 && ops.size() == 0;
         this.lir = newLir;
     }
 
@@ -126,32 +127,38 @@
                 }
                 ipIndex--;
             }
-            indexAndCount.clear();
+            indexAndCountSize = 0;
             ops.clear();
         }
         lir = null;
     }
 
     private void appendNew(int index, int count) {
-        indexAndCount.add(index);
-        indexAndCount.add(count);
+        int oldSize = indexAndCountSize;
+        int newSize = oldSize + 2;
+        if (newSize > this.indexAndCount.length) {
+            indexAndCount = Arrays.copyOf(indexAndCount, newSize * 2);
+        }
+        indexAndCount[oldSize] = index;
+        indexAndCount[oldSize + 1] = count;
+        this.indexAndCountSize = newSize;
     }
 
     private void setCountAt(int i, int value) {
-        indexAndCount.set((i << 1) + 1, value);
+        indexAndCount[(i << 1) + 1] = value;
     }
 
     private int numberOfInsertionPoints() {
-        assert indexAndCount.size() % 2 == 0 : "must have a count for each index";
-        return indexAndCount.size() >> 1;
+        assert indexAndCount.length % 2 == 0 : "must have a count for each index";
+        return indexAndCountSize >> 1;
     }
 
     private int indexAt(int i) {
-        return indexAndCount.get((i << 1));
+        return indexAndCount[(i << 1)];
     }
 
     private int countAt(int i) {
-        return indexAndCount.get((i << 1) + 1);
+        return indexAndCount[(i << 1) + 1];
     }
 
     private boolean verify() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import java.util.function.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+public class LoopPeelingPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
+            LoopsData data = new LoopsData(graph);
+            for (LoopEx loop : data.outerFirst()) {
+                if (LoopPolicies.shouldPeel(loop, probabilities)) {
+                    Debug.log("Peeling %s", loop);
+                    LoopTransformations.peel(loop);
+                    Debug.dump(graph, "After peeling %s", loop);
+                }
+            }
+            data.deleteUnusedNodes();
+        }
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Sat Jan 31 15:51:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.loop.phases;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import java.util.function.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.loop.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-
-public class LoopTransformHighPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            if (LoopPeeling.getValue()) {
-                ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
-                LoopsData data = new LoopsData(graph);
-                for (LoopEx loop : data.outerFirst()) {
-                    if (LoopPolicies.shouldPeel(loop, probabilities)) {
-                        Debug.log("Peeling %s", loop);
-                        LoopTransformations.peel(loop);
-                        Debug.dump(graph, "After peeling %s", loop);
-                    }
-                }
-                data.deleteUnusedNodes();
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Sat Jan 31 15:51:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.loop.phases;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.loop.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-
-public class LoopTransformLowPhase extends Phase {
-
-    private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
-    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            if (ReassociateInvariants.getValue()) {
-                final LoopsData dataReassociate = new LoopsData(graph);
-                try (Scope s = Debug.scope("ReassociateInvariants")) {
-                    for (LoopEx loop : dataReassociate.loops()) {
-                        loop.reassociateInvariants();
-                    }
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-                dataReassociate.deleteUnusedNodes();
-            }
-            if (LoopUnswitch.getValue()) {
-                boolean unswitched;
-                do {
-                    unswitched = false;
-                    final LoopsData dataUnswitch = new LoopsData(graph);
-                    for (LoopEx loop : dataUnswitch.loops()) {
-                        if (LoopPolicies.shouldTryUnswitch(loop)) {
-                            List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
-                            if (controlSplits != null) {
-                                UNSWITCH_CANDIDATES.increment();
-                                if (LoopPolicies.shouldUnswitch(loop, controlSplits)) {
-                                    if (Debug.isLogEnabled()) {
-                                        logUnswitch(loop, controlSplits);
-                                    }
-                                    LoopTransformations.unswitch(loop, controlSplits);
-                                    UNSWITCHED.increment();
-                                    unswitched = true;
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                } while (unswitched);
-            }
-        }
-    }
-
-    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
-        StringBuilder sb = new StringBuilder("Unswitching ");
-        sb.append(loop).append(" at ");
-        for (ControlSplitNode controlSplit : controlSplits) {
-            sb.append(controlSplit).append(" [");
-            NodePosIterator it = controlSplit.successors().iterator();
-            while (it.hasNext()) {
-                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
-                if (it.hasNext()) {
-                    sb.append(", ");
-                }
-            }
-            sb.append("]");
-        }
-        Debug.log("%s", sb);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class LoopUnswitchingPhase extends Phase {
+
+    private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
+    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            boolean unswitched;
+            do {
+                unswitched = false;
+                final LoopsData dataUnswitch = new LoopsData(graph);
+                for (LoopEx loop : dataUnswitch.loops()) {
+                    if (LoopPolicies.shouldTryUnswitch(loop)) {
+                        List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
+                        if (controlSplits != null) {
+                            UNSWITCH_CANDIDATES.increment();
+                            if (LoopPolicies.shouldUnswitch(loop, controlSplits)) {
+                                if (Debug.isLogEnabled()) {
+                                    logUnswitch(loop, controlSplits);
+                                }
+                                LoopTransformations.unswitch(loop, controlSplits);
+                                UNSWITCHED.increment();
+                                unswitched = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+            } while (unswitched);
+        }
+    }
+
+    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
+        StringBuilder sb = new StringBuilder("Unswitching ");
+        sb.append(loop).append(" at ");
+        for (ControlSplitNode controlSplit : controlSplits) {
+            sb.append(controlSplit).append(" [");
+            NodePosIterator it = controlSplit.successors().iterator();
+            while (it.hasNext()) {
+                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
+                if (it.hasNext()) {
+                    sb.append(", ");
+                }
+            }
+            sb.append("]");
+        }
+        Debug.log("%s", sb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class ReassociateInvariantPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            final LoopsData dataReassociate = new LoopsData(graph);
+            try (Scope s = Debug.scope("ReassociateInvariants")) {
+                for (LoopEx loop : dataReassociate.loops()) {
+                    loop.reassociateInvariants();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            dataReassociate.deleteUnusedNodes();
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Tue Feb 03 11:10:24 2015 +0100
@@ -42,7 +42,7 @@
             this.direct = direct;
         }
 
-        private boolean direct;
+        private final boolean direct;
 
         public boolean hasReceiver() {
             return this != Static;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Tue Feb 03 11:10:24 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.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue Feb 03 11:10:24 2015 +0100
@@ -56,27 +56,31 @@
         gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(getValue()));
     }
 
+    /**
+     * Determines if the compiler should emit code to test whether a given object has a finalizer
+     * that must be registered with the runtime upon object initialization.
+     */
+    public static boolean mayHaveFinalizer(ValueNode object, Assumptions assumptions) {
+        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+        if (objectStamp.isExactType()) {
+            return objectStamp.type().hasFinalizer();
+        } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
+            // if either the declared type of receiver or the holder
+            // can be assumed to have no finalizers
+            if (assumptions.useOptimisticAssumptions()) {
+                assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type());
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (!(forValue.stamp() instanceof ObjectStamp)) {
             return this;
         }
-
-        ObjectStamp objectStamp = (ObjectStamp) forValue.stamp();
-
-        boolean needsCheck = true;
-        if (objectStamp.isExactType()) {
-            needsCheck = objectStamp.type().hasFinalizer();
-        } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
-            // if either the declared type of receiver or the holder
-            // can be assumed to have no finalizers
-            if (tool.assumptions().useOptimisticAssumptions()) {
-                tool.assumptions().recordNoFinalizableSubclassAssumption(objectStamp.type());
-                needsCheck = false;
-            }
-        }
-
-        if (!needsCheck) {
+        if (!mayHaveFinalizer(forValue, tool.assumptions())) {
             return null;
         }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Feb 03 11:10:24 2015 +0100
@@ -641,177 +641,210 @@
         @Override
         protected void node(FixedNode node) {
             if (node instanceof AbstractBeginNode) {
-                AbstractBeginNode begin = (AbstractBeginNode) node;
-                Node pred = node.predecessor();
+                processAbstractBegin((AbstractBeginNode) node);
+            } else if (node instanceof FixedGuardNode) {
+                processFixedGuard((FixedGuardNode) node);
+            } else if (node instanceof CheckCastNode) {
+                processCheckCast((CheckCastNode) node);
+            } else if (node instanceof ConditionAnchorNode) {
+                processConditionAnchor((ConditionAnchorNode) node);
+            } else if (node instanceof IfNode) {
+                processIf((IfNode) node);
+            } else if (node instanceof AbstractEndNode) {
+                processAbstractEnd((AbstractEndNode) node);
+            } else if (node instanceof Invoke) {
+                processInvoke((Invoke) node);
+            }
+        }
 
-                if (pred != null) {
-                    registerControlSplitInfo(pred, begin);
-                }
-
-                // First eliminate any guards which can be trivially removed and register any
-                // type constraints the guards produce.
-                for (GuardNode guard : begin.guards().snapshot()) {
-                    eliminateTrivialGuardOrRegisterStamp(guard);
-                }
+        private void processIf(IfNode ifNode) {
+            LogicNode compare = ifNode.condition();
 
-                // Collect the guards which have produced conditional stamps.
-                // XXX (gd) IdentityHashMap.values().contains performs a linear search
-                // so we prefer to build a set
-                Set<GuardNode> provers = Node.newSet();
-                for (GuardedStamp e : state.valueConstraints.values()) {
-                    provers.add(e.getGuard());
-                }
-
-                // Process the remaining guards. Guards which produced some type constraint should
-                // just be registered since they aren't trivially deleteable. Test the other guards
-                // to see if they can be deleted using type constraints.
-                for (GuardNode guard : begin.guards().snapshot()) {
-                    if (provers.contains(guard) || !(tryReplaceWithExistingGuard(guard) || testImpliedGuard(guard))) {
-                        registerCondition(!guard.isNegated(), guard.condition(), guard);
+            LogicNode replacement = null;
+            GuardingNode replacementAnchor = null;
+            AbstractBeginNode survivingSuccessor = null;
+            if (state.trueConditions.containsKey(compare)) {
+                replacement = trueConstant;
+                replacementAnchor = state.trueConditions.get(compare);
+                survivingSuccessor = ifNode.trueSuccessor();
+            } else if (state.falseConditions.containsKey(compare)) {
+                replacement = falseConstant;
+                replacementAnchor = state.falseConditions.get(compare);
+                survivingSuccessor = ifNode.falseSuccessor();
+            } else {
+                replacement = evaluateCondition(compare, trueConstant, falseConstant);
+                if (replacement != null) {
+                    if (replacement == trueConstant) {
+                        survivingSuccessor = ifNode.trueSuccessor();
+                    } else {
+                        assert replacement == falseConstant;
+                        survivingSuccessor = ifNode.falseSuccessor();
                     }
                 }
-                for (GuardNode guard : provers) {
-                    assert !testImpliedGuard(guard) : "provers shouldn't be trivially eliminatable";
-                }
-            } else if (node instanceof FixedGuardNode) {
-                FixedGuardNode guard = (FixedGuardNode) node;
-                GuardingNode existingGuard = guard.isNegated() ? state.falseConditions.get(guard.condition()) : state.trueConditions.get(guard.condition());
-                if (existingGuard != null && existingGuard instanceof FixedGuardNode) {
-                    guard.replaceAtUsages(existingGuard.asNode());
-                    guard.graph().removeFixed(guard);
-                } else {
-                    registerCondition(!guard.isNegated(), guard.condition(), guard);
-                }
-            } else if (node instanceof CheckCastNode) {
-                CheckCastNode checkCast = (CheckCastNode) node;
-                ValueNode object = checkCast.object();
-                boolean isNull = state.isNull(object);
-                ResolvedJavaType type = state.getNodeType(object);
-                if (isNull || (type != null && checkCast.type().isAssignableFrom(type))) {
-                    boolean nonNull = state.isNonNull(object);
-                    GuardingNode replacementAnchor = null;
-                    if (nonNull) {
-                        replacementAnchor = searchAnchor(GraphUtil.unproxify(object), type);
-                    }
-                    if (replacementAnchor == null) {
-                        replacementAnchor = AbstractBeginNode.prevBegin(checkCast);
-                    }
-                    PiNode piNode;
-                    if (isNull) {
-                        ConstantNode nullObject = ConstantNode.defaultForKind(Kind.Object, graph);
-                        piNode = graph.unique(new PiNode(nullObject, nullObject.stamp(), replacementAnchor.asNode()));
-                    } else {
-                        piNode = graph.unique(new PiNode(object, StampFactory.declaredTrusted(type, nonNull), replacementAnchor.asNode()));
-                    }
-                    checkCast.replaceAtUsages(piNode);
-                    graph.removeFixed(checkCast);
-                    metricCheckCastRemoved.increment();
-                }
-            } else if (node instanceof ConditionAnchorNode) {
-                ConditionAnchorNode conditionAnchorNode = (ConditionAnchorNode) node;
-                LogicNode condition = conditionAnchorNode.condition();
-                GuardingNode replacementAnchor = null;
-                if (conditionAnchorNode.isNegated()) {
-                    if (state.falseConditions.containsKey(condition)) {
-                        replacementAnchor = state.falseConditions.get(condition);
-                    }
-                } else {
-                    if (state.trueConditions.containsKey(condition)) {
-                        replacementAnchor = state.trueConditions.get(condition);
-                    }
-                }
-                if (replacementAnchor != null) {
-                    conditionAnchorNode.replaceAtUsages(replacementAnchor.asNode());
-                    conditionAnchorNode.graph().removeFixed(conditionAnchorNode);
-                }
-            } else if (node instanceof IfNode) {
-                IfNode ifNode = (IfNode) node;
-                LogicNode compare = ifNode.condition();
+            }
+
+            if (replacement != null) {
+                trySimplify(ifNode, compare, replacement, replacementAnchor, survivingSuccessor);
+            }
+        }
 
-                LogicNode replacement = null;
-                GuardingNode replacementAnchor = null;
-                AbstractBeginNode survivingSuccessor = null;
-                if (state.trueConditions.containsKey(compare)) {
-                    replacement = trueConstant;
-                    replacementAnchor = state.trueConditions.get(compare);
-                    survivingSuccessor = ifNode.trueSuccessor();
-                } else if (state.falseConditions.containsKey(compare)) {
-                    replacement = falseConstant;
-                    replacementAnchor = state.falseConditions.get(compare);
-                    survivingSuccessor = ifNode.falseSuccessor();
+        private void trySimplify(IfNode ifNode, LogicNode compare, LogicNode replacement, GuardingNode replacementAnchor, AbstractBeginNode survivingSuccessor) {
+            if (replacementAnchor != null && !(replacementAnchor instanceof AbstractBeginNode)) {
+                ValueAnchorNode anchor = graph.add(new ValueAnchorNode(replacementAnchor.asNode()));
+                graph.addBeforeFixed(ifNode, anchor);
+            }
+            boolean canSimplify = true;
+            for (Node n : survivingSuccessor.usages().snapshot()) {
+                if (n instanceof GuardNode || n instanceof ProxyNode) {
+                    // Keep wired to the begin node.
                 } else {
-                    replacement = evaluateCondition(compare, trueConstant, falseConstant);
-                    if (replacement != null) {
-                        if (replacement == trueConstant) {
-                            survivingSuccessor = ifNode.trueSuccessor();
-                        } else {
-                            assert replacement == falseConstant;
-                            survivingSuccessor = ifNode.falseSuccessor();
-                        }
-                    }
-                }
-
-                if (replacement != null) {
-                    if (replacementAnchor != null && !(replacementAnchor instanceof AbstractBeginNode)) {
-                        ValueAnchorNode anchor = graph.add(new ValueAnchorNode(replacementAnchor.asNode()));
-                        graph.addBeforeFixed(ifNode, anchor);
+                    if (replacementAnchor == null) {
+                        // Cannot simplify this IfNode as there is no anchor.
+                        canSimplify = false;
+                        break;
                     }
-                    for (Node n : survivingSuccessor.usages().snapshot()) {
-                        if (n instanceof GuardNode || n instanceof ProxyNode) {
-                            // Keep wired to the begin node.
-                        } else {
-                            if (replacementAnchor == null) {
-                                // Cannot simplify this IfNode as there is no anchor.
-                                return;
-                            }
-                            // Rewire to the replacement anchor.
-                            n.replaceFirstInput(survivingSuccessor, replacementAnchor.asNode());
-                        }
-                    }
+                    // Rewire to the replacement anchor.
+                    n.replaceFirstInput(survivingSuccessor, replacementAnchor.asNode());
+                }
+            }
+
+            if (canSimplify) {
+                ifNode.setCondition(replacement);
+                if (compare.hasNoUsages()) {
+                    GraphUtil.killWithUnusedFloatingInputs(compare);
+                }
+            }
+        }
 
-                    ifNode.setCondition(replacement);
-                    if (compare.hasNoUsages()) {
-                        GraphUtil.killWithUnusedFloatingInputs(compare);
-                    }
-                }
-            } else if (node instanceof AbstractEndNode) {
-                AbstractEndNode endNode = (AbstractEndNode) node;
-                for (PhiNode phi : endNode.merge().phis()) {
-                    int index = endNode.merge().phiPredecessorIndex(endNode);
-                    ValueNode value = phi.valueAt(index);
-                    if (value instanceof ConditionalNode) {
-                        ConditionalNode materialize = (ConditionalNode) value;
-                        LogicNode compare = materialize.condition();
-                        ValueNode replacement = evaluateCondition(compare, materialize.trueValue(), materialize.falseValue());
-
-                        if (replacement != null) {
-                            phi.setValueAt(index, replacement);
-                            if (materialize.hasNoUsages()) {
-                                GraphUtil.killWithUnusedFloatingInputs(materialize);
+        private void processInvoke(Invoke invoke) {
+            if (invoke.callTarget() instanceof MethodCallTargetNode) {
+                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+                ValueNode receiver = callTarget.receiver();
+                if (receiver != null && callTarget.invokeKind().isIndirect()) {
+                    ResolvedJavaType type = state.getNodeType(receiver);
+                    if (!Objects.equals(type, StampTool.typeOrNull(receiver))) {
+                        ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), invoke.getContextType());
+                        if (method != null) {
+                            if (method.canBeStaticallyBound() || type.isFinal()) {
+                                callTarget.setInvokeKind(InvokeKind.Special);
+                                callTarget.setTargetMethod(method);
                             }
                         }
                     }
                 }
-            } else if (node instanceof Invoke) {
-                Invoke invoke = (Invoke) node;
-                if (invoke.callTarget() instanceof MethodCallTargetNode) {
-                    MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-                    ValueNode receiver = callTarget.receiver();
-                    if (receiver != null && callTarget.invokeKind().isIndirect()) {
-                        ResolvedJavaType type = state.getNodeType(receiver);
-                        if (!Objects.equals(type, StampTool.typeOrNull(receiver))) {
-                            ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), invoke.getContextType());
-                            if (method != null) {
-                                if (method.canBeStaticallyBound() || type.isFinal()) {
-                                    callTarget.setInvokeKind(InvokeKind.Special);
-                                    callTarget.setTargetMethod(method);
-                                }
-                            }
+            }
+        }
+
+        private void processAbstractEnd(AbstractEndNode endNode) {
+            for (PhiNode phi : endNode.merge().phis()) {
+                int index = endNode.merge().phiPredecessorIndex(endNode);
+                ValueNode value = phi.valueAt(index);
+                if (value instanceof ConditionalNode) {
+                    ConditionalNode materialize = (ConditionalNode) value;
+                    LogicNode compare = materialize.condition();
+                    ValueNode replacement = evaluateCondition(compare, materialize.trueValue(), materialize.falseValue());
+
+                    if (replacement != null) {
+                        phi.setValueAt(index, replacement);
+                        if (materialize.hasNoUsages()) {
+                            GraphUtil.killWithUnusedFloatingInputs(materialize);
                         }
                     }
                 }
+            }
+        }
 
+        private void processConditionAnchor(ConditionAnchorNode conditionAnchorNode) {
+            LogicNode condition = conditionAnchorNode.condition();
+            GuardingNode replacementAnchor = null;
+            if (conditionAnchorNode.isNegated()) {
+                if (state.falseConditions.containsKey(condition)) {
+                    replacementAnchor = state.falseConditions.get(condition);
+                }
+            } else {
+                if (state.trueConditions.containsKey(condition)) {
+                    replacementAnchor = state.trueConditions.get(condition);
+                }
             }
+            if (replacementAnchor != null) {
+                conditionAnchorNode.replaceAtUsages(replacementAnchor.asNode());
+                conditionAnchorNode.graph().removeFixed(conditionAnchorNode);
+            }
+        }
+
+        private void processCheckCast(CheckCastNode checkCast) {
+            ValueNode object = checkCast.object();
+            boolean isNull = state.isNull(object);
+            ResolvedJavaType type = state.getNodeType(object);
+            if (isNull || (type != null && checkCast.type().isAssignableFrom(type))) {
+                boolean nonNull = state.isNonNull(object);
+                GuardingNode replacementAnchor = null;
+                if (nonNull) {
+                    replacementAnchor = searchAnchor(GraphUtil.unproxify(object), type);
+                }
+                if (replacementAnchor == null) {
+                    replacementAnchor = AbstractBeginNode.prevBegin(checkCast);
+                }
+                PiNode piNode;
+                if (isNull) {
+                    ConstantNode nullObject = ConstantNode.defaultForKind(Kind.Object, graph);
+                    piNode = graph.unique(new PiNode(nullObject, nullObject.stamp(), replacementAnchor.asNode()));
+                } else {
+                    piNode = graph.unique(new PiNode(object, StampFactory.declaredTrusted(type, nonNull), replacementAnchor.asNode()));
+                }
+                checkCast.replaceAtUsages(piNode);
+                graph.removeFixed(checkCast);
+                metricCheckCastRemoved.increment();
+            }
+        }
+
+        private void processFixedGuard(FixedGuardNode guard) {
+            GuardingNode existingGuard = guard.isNegated() ? state.falseConditions.get(guard.condition()) : state.trueConditions.get(guard.condition());
+            if (existingGuard != null && existingGuard instanceof FixedGuardNode) {
+                guard.replaceAtUsages(existingGuard.asNode());
+                guard.graph().removeFixed(guard);
+            } else {
+                registerCondition(!guard.isNegated(), guard.condition(), guard);
+            }
+        }
+
+        private void processAbstractBegin(AbstractBeginNode begin) {
+            Node pred = begin.predecessor();
+
+            if (pred != null) {
+                registerControlSplitInfo(pred, begin);
+            }
+
+            // First eliminate any guards which can be trivially removed and register any
+            // type constraints the guards produce.
+            for (GuardNode guard : begin.guards().snapshot()) {
+                eliminateTrivialGuardOrRegisterStamp(guard);
+            }
+
+            // Collect the guards which have produced conditional stamps.
+            // XXX (gd) IdentityHashMap.values().contains performs a linear search
+            // so we prefer to build a set
+            Set<GuardNode> provers = Node.newSet();
+            for (GuardedStamp e : state.valueConstraints.values()) {
+                provers.add(e.getGuard());
+            }
+
+            // Process the remaining guards. Guards which produced some type constraint should
+            // just be registered since they aren't trivially deleteable. Test the other guards
+            // to see if they can be deleted using type constraints.
+            for (GuardNode guard : begin.guards().snapshot()) {
+                if (provers.contains(guard) || !(tryReplaceWithExistingGuard(guard) || testImpliedGuard(guard))) {
+                    registerCondition(!guard.isNegated(), guard.condition(), guard);
+                }
+            }
+            assert assertImpliedGuard(provers);
+        }
+
+        private boolean assertImpliedGuard(Set<GuardNode> provers) {
+            for (GuardNode guard : provers) {
+                assert !testImpliedGuard(guard) : "provers shouldn't be trivially eliminatable";
+            }
+            return true;
         }
 
         private GuardingNode searchAnchor(ValueNode value, ResolvedJavaType type) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Feb 03 11:10:24 2015 +0100
@@ -1068,7 +1068,13 @@
     }
 
     private void addToLatestSorting(ValueNode i, SortState state) {
-        if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode || i instanceof ProxyNode) {
+        if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) {
+            return;
+        }
+
+        if (i instanceof ProxyNode) {
+            ProxyNode proxyNode = (ProxyNode) i;
+            addToLatestSorting(proxyNode.value(), state);
             return;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Tue Feb 03 11:10:24 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,18 +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);
-                replacements.registerSubstitutions(new Type() {
-                    public String getTypeName() {
-                        return "org.openjdk.jmh.logic.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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Feb 03 11:10:24 2015 +0100
@@ -113,11 +113,13 @@
                         }
                         String originalName = originalName(substituteMethod, methodSubstitution.value());
                         JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
-                        Executable originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
-                        if (originalMethod != null && (guard == null || guard.execute())) {
-                            ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
-                            if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
-                                forcedSubstitutions.add(original);
+                        Executable[] originalMethods = originalMethods(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
+                        for (Executable originalMethod : originalMethods) {
+                            if (originalMethod != null && (guard == null || guard.execute())) {
+                                ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
+                                if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
+                                    forcedSubstitutions.add(original);
+                                }
                             }
                         }
                     }
@@ -126,11 +128,13 @@
                     if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) {
                         String originalName = originalName(substituteMethod, macroSubstitution.value());
                         JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
-                        Executable originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
-                        if (originalMethod != null) {
-                            ResolvedJavaMethod original = registerMacroSubstitution(this, originalMethod, macroSubstitution.macro());
-                            if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
-                                forcedSubstitutions.add(original);
+                        Executable[] originalMethods = originalMethods(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
+                        for (Executable originalMethod : originalMethods) {
+                            if (originalMethod != null) {
+                                ResolvedJavaMethod original = registerMacroSubstitution(this, originalMethod, macroSubstitution.macro());
+                                if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
+                                    forcedSubstitutions.add(original);
+                                }
                             }
                         }
                     }
@@ -159,20 +163,30 @@
             return new JavaSignature(returnType, parameters);
         }
 
-        private Executable originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
+        private Executable[] originalMethods(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
             Class<?> originalClass = classSubstitution.value();
             if (originalClass == ClassSubstitution.class) {
+                ArrayList<Executable> result = new ArrayList<>();
                 for (String className : classSubstitution.className()) {
                     originalClass = resolveClass(className, classSubstitution.optional());
                     if (originalClass != null) {
-                        break;
+                        result.add(lookupOriginalMethod(originalClass, name, signature, optional));
                     }
                 }
-                if (originalClass == null) {
+                if (result.size() == 0) {
                     // optional class was not found
                     return null;
                 }
+                return result.toArray(new Executable[result.size()]);
             }
+            Executable original = lookupOriginalMethod(originalClass, name, signature, optional);
+            if (original != null) {
+                return new Executable[]{original};
+            }
+            return null;
+        }
+
+        private Executable lookupOriginalMethod(Class<?> originalClass, String name, JavaSignature signature, boolean optional) throws GraalInternalError {
             try {
                 if (name.equals("<init>")) {
                     assert signature.returnType.equals(void.class) : signature;
@@ -605,7 +619,8 @@
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    createGraphBuilder(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(
+                                    graph);
                 }
                 afterParsing(graph);
 
@@ -618,8 +633,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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BlackholeNode.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Tue Feb 03 11:10:24 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	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Feb 03 11:10:24 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/PartialEvaluator.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Feb 03 11:10:24 2015 +0100
@@ -137,49 +137,20 @@
             HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
 
             // EA frame and clean up.
-            try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
-                new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
-                new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext);
-            } catch (Throwable t) {
-                Debug.handle(t);
-            }
-
-            // to make frame propagations visible retry expandTree
-            while (expandTree(graph, assumptions, expansionLogger)) {
+            do {
                 try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
                     new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
                     new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext);
                 } catch (Throwable t) {
                     Debug.handle(t);
                 }
-            }
+            } while (expandTree(graph, assumptions, expansionLogger));
 
             if (expansionLogger != null) {
                 expansionLogger.print(callTarget);
             }
 
-            for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
-                Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
-                throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
-            }
-
-            new VerifyNoIntrinsicsLeftPhase().apply(graph, false);
-            for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
-                materializeNode.replaceAtUsages(materializeNode.getFrame());
-                graph.removeFixed(materializeNode);
-            }
-            for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
-                if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
-                    VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
-                    virtualOnlyInstanceNode.setAllowMaterialization(true);
-                } else if (virtualObjectNode instanceof VirtualInstanceNode) {
-                    VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode;
-                    ResolvedJavaType type = virtualInstanceNode.type();
-                    if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) {
-                        virtualInstanceNode.setIdentity(false);
-                    }
-                }
-            }
+            postPartialEvaluation(graph);
 
         } catch (Throwable e) {
             throw Debug.handle(e);
@@ -188,6 +159,26 @@
         return graph;
     }
 
+    private static void postPartialEvaluation(final StructuredGraph graph) {
+        NeverPartOfCompilationNode.verifyNotFoundIn(graph);
+        for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
+            materializeNode.replaceAtUsages(materializeNode.getFrame());
+            graph.removeFixed(materializeNode);
+        }
+        for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
+            if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
+                VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
+                virtualOnlyInstanceNode.setAllowMaterialization(true);
+            } else if (virtualObjectNode instanceof VirtualInstanceNode) {
+                VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode;
+                ResolvedJavaType type = virtualInstanceNode.type();
+                if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) {
+                    virtualInstanceNode.setIdentity(false);
+                }
+            }
+        }
+    }
+
     private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) {
         ParameterNode thisNode = graph.getParameter(0);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Feb 03 11:10:24 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.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Feb 03 11:10:24 2015 +0100
@@ -176,5 +176,8 @@
 
     @Option(help = "Print additional more verbose Truffle compilation statistics at the end of a run.", type = OptionType.Debug)
     public static final OptionValue<Boolean> TruffleCompilationStatisticDetails = new OptionValue<>(false);
+
+    @Option(help = "Experimental new version of the partial evaluator.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> FastPE = new OptionValue<>(false);
     // @formatter:on
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Tue Feb 03 11:10:24 2015 +0100
@@ -144,7 +144,12 @@
     }
 
     public TruffleInliningDecision findByCall(OptimizedDirectCallNode callNode) {
-        return getCallSites().stream().filter(c -> c.getProfile().getCallNode() == callNode).findFirst().orElse(null);
+        for (TruffleInliningDecision d : getCallSites()) {
+            if (d.getProfile().getCallNode() == callNode) {
+                return d;
+            }
+        }
+        return null;
     }
 
     /**
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Sat Jan 31 15:51:54 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Tue Feb 03 11:10:24 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -44,4 +45,11 @@
     public final String getMessage() {
         return message + " " + arguments.toString();
     }
+
+    public static void verifyNotFoundIn(final StructuredGraph graph) {
+        for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
+            Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
+            throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
+        }
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java	Sat Jan 31 15:51:54 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.phases;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.frame.*;
-
-/**
- * Verification phase for checking that no frame intrinsic nodes introduced by the
- * {@link PartialEvaluator} are still in the graph.
- */
-public class VerifyNoIntrinsicsLeftPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        verifyNoInstanceLeft(graph, NewFrameNode.class);
-    }
-
-    public static <T extends Node & IterableNodeType> void verifyNoInstanceLeft(StructuredGraph graph, Class<T> clazz) {
-        if (graph.getNodes(clazz).count() != 0) {
-            throw new VerificationError("Found unexpected node(s): %s", graph.getNodes(clazz));
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Tue Feb 03 11:10:24 2015 +0100
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.substitutions;
+
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.truffle.nodes.frame.*;
+import com.oracle.truffle.api.*;
+
+/**
+ * Provider of {@link GraphBuilderPlugin}s for Truffle classes.
+ */
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        plugins.register(metaAccess, CompilerDirectivesPlugin.class);
+    }
+
+    /**
+     * Plugins for {@link CompilerDirectives}.
+     */
+    enum CompilerDirectivesPlugin implements GraphBuilderPlugin {
+        inInterpreter() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(ConstantNode.forBoolean(false));
+                return true;
+            }
+        },
+        inCompiledCode() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(ConstantNode.forBoolean(true));
+                return true;
+            }
+        },
+        transferToInterpreter() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        },
+        transferToInterpreterAndInvalidate() {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        },
+        interpreterOnly(Runnable.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                return true;
+            }
+        },
+        interpreterOnly$(Callable.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                return true;
+            }
+        },
+        injectBranchProbability(double.class, boolean.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                ValueNode probability = args[0];
+                ValueNode condition = args[1];
+                builder.append(new BranchProbabilityNode(probability, condition));
+                return true;
+            }
+        },
+        bailout(String.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                // TODO: is this too eager? Should a BailoutNode be created instead?
+                ValueNode message = args[0];
+                if (message.isConstant()) {
+                    throw new BailoutException(message.asConstant().toValueString());
+                }
+                throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)");
+            }
+        },
+
+        isCompilationConstant(Object.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                ValueNode arg0 = args[0];
+                if (arg0 instanceof BoxNode) {
+                    arg0 = ((BoxNode) arg0).getValue();
+                }
+                if (arg0.isConstant()) {
+                    builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
+                    return true;
+                }
+
+                // Cannot create MacroNodes in a plugin (yet)
+                return false;
+            }
+        },
+        materialize(Object.class) {
+            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+                builder.append(new ForceMaterializeNode(args[0]));
+                return true;
+            }
+        };
+
+        CompilerDirectivesPlugin(Class<?>... parameterTypes) {
+            this.parameterTypes = parameterTypes;
+        }
+
+        private final Class<?>[] parameterTypes;
+
+        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
+            return GraphBuilderPlugin.resolveTarget(metaAccess, CompilerDirectives.class, name(), parameterTypes);
+        }
+    }
+}
--- a/mx/mx_graal.py	Sat Jan 31 15:51:54 2015 +0100
+++ b/mx/mx_graal.py	Tue Feb 03 11:10:24 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	Sat Jan 31 15:51:54 2015 +0100
+++ b/mx/suite.py	Tue Feb 03 11:10:24 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",