changeset 7070:c2a3b92c9e79

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Mon, 26 Nov 2012 10:57:02 +0100
parents e5ec98288b91 (current diff) 17eeac928874 (diff)
children b7da4418a7c3
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/AddressMap.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java src/share/vm/graal/graalCodeInstaller.cpp
diffstat 36 files changed, 1464 insertions(+), 1346 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Mon Nov 26 10:57:02 2012 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2011, 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.meta.test;
+
+import static com.oracle.graal.api.meta.MetaUtil.*;
+import static org.junit.Assert.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+
+
+public class TestMetaAccessProvider {
+
+    public TestMetaAccessProvider() {
+    }
+
+    public static final MetaAccessProvider runtime = Graal.getRequiredCapability(MetaAccessProvider.class);
+    public static final List<Class<?>> classes = new ArrayList<>(Arrays.asList(
+        void.class,
+        boolean.class,
+        byte.class,
+        short.class,
+        char.class,
+        int.class,
+        float.class,
+        long.class,
+        double.class,
+        Object.class,
+        Serializable.class,
+        Cloneable.class,
+        Test.class,
+        TestMetaAccessProvider.class
+    ));
+
+    static {
+        for (Class<?> c : new ArrayList<>(classes)) {
+            if (c != void.class) {
+                classes.add(Array.newInstance(c, 0).getClass());
+            }
+        }
+    }
+
+    @Test
+    public void lookupJavaTypeTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            assertNotNull(type);
+            assertTrue(type.isClass(c));
+            assertEquals(c.getModifiers(), type.getModifiers());
+            if (!type.isArrayClass()) {
+                assertEquals(type.getName(), toInternalName(c.getName()));
+                assertEquals(toJavaName(type), c.getName());
+            }
+        }
+    }
+
+    @Test
+    public void lookupJavaMethodTest() {
+        for (Class c : classes) {
+            for (Method reflect : c.getDeclaredMethods()) {
+                ResolvedJavaMethod method = runtime.lookupJavaMethod(reflect);
+                assertNotNull(method);
+                assertEquals(reflect.getModifiers(), method.getModifiers());
+                assertTrue(method.getDeclaringClass().isClass(reflect.getDeclaringClass()));
+            }
+        }
+    }
+
+    @Test
+    public void lookupJavaFieldTest() {
+        for (Class c : classes) {
+            for (Field reflect : c.getDeclaredFields()) {
+                ResolvedJavaField field = runtime.lookupJavaField(reflect);
+                assertNotNull(field);
+                assertEquals(reflect.getModifiers(), field.getModifiers());
+                assertTrue(field.getDeclaringClass().isClass(reflect.getDeclaringClass()));
+            }
+        }
+    }
+
+    public static final List<Constant> constants = new ArrayList<>();
+    static {
+        for (Field f : Constant.class.getDeclaredFields()) {
+            int mods = f.getModifiers();
+            if (f.getType() == Constant.class && Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
+                try {
+                    Constant c = (Constant) f.get(null);
+                    if (c != null) {
+                        constants.add(c);
+                    }
+                } catch (Exception e) {
+                }
+            }
+        }
+        for (Class c : classes) {
+            if (c != void.class) {
+                constants.add(Constant.forObject(Array.newInstance(c, 42)));
+            }
+        }
+    }
+
+    @Test
+    public void lookupJavaTypeConstantTest() {
+        for (Constant c : constants) {
+            if (c.getKind().isObject() && !c.isNull()) {
+                Object o = c.asObject();
+                ResolvedJavaType type = runtime.lookupJavaType(c);
+                assertNotNull(type);
+                assertTrue(type.isClass(o.getClass()));
+            } else {
+                assertEquals(runtime.lookupJavaType(c), null);
+            }
+        }
+    }
+
+    @Test
+    public void constantEqualsTest() {
+        for (Constant c1 : constants) {
+            for (Constant c2 : constants) {
+                // test symmetry
+                assertEquals(runtime.constantEquals(c1, c2), runtime.constantEquals(c2, c1));
+                if (!c1.getKind().isObject() && !c2.getKind().isObject()) {
+                    assertEquals(c1.equals(c2), runtime.constantEquals(c2, c1));
+                }
+            }
+        }
+    }
+
+    @Test
+    public void lookupArrayLengthTest() {
+        for (Constant c : constants) {
+            if (!c.getKind().isObject() || c.isNull() || !c.asObject().getClass().isArray()) {
+                try {
+                    int length = runtime.lookupArrayLength(c);
+                    fail("Expected " + IllegalArgumentException.class.getName() + " for " + c + ", not " + length);
+                } catch (IllegalArgumentException e) {
+                    // pass
+                }
+            } else {
+                assertEquals(Array.getLength(c.asObject()), runtime.lookupArrayLength(c));
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Mon Nov 26 10:57:02 2012 +0100
@@ -56,8 +56,10 @@
 
     /**
      * Compares two constants for equality.
-     * This is used instead of {@link Constant#equals(Object)} in case where the runtime
-     * may have an interpretation for object equality other than {@code x.asObject() == y.asObject()}.
+     * This is used instead of {@link Constant#equals(Object)} in case the runtime
+     * has an interpretation for object equality other than {@code x.asObject() == y.asObject()}.
+     * For primitive constants, this is equivalent to calling {@code x.equals(y)}.
+     * The equality relationship is symmetric.
      *
      * @return {@code true} if the two parameters represent the same runtime object, {@code false} otherwise
      */
@@ -65,6 +67,8 @@
 
     /**
      * Returns the length of an array that is wrapped in a {@link Constant} object.
+     *
+     * @throws IllegalArgumentException if {@code array} is not an array
      */
     int lookupArrayLength(Constant array);
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Mon Nov 26 10:57:02 2012 +0100
@@ -46,9 +46,16 @@
     }
 
     /**
+     * Determines if a given type represents a primitive type.
+     */
+    public static boolean isPrimitive(ResolvedJavaType type) {
+        return type.getSuperclass() == null && !type.isInstanceClass();
+    }
+
+    /**
      * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for anonymous and local
      * classes.
-     * 
+     *
      * @param clazz the class for which the simple name is being requested
      * @param withEnclosingClass specifies if the returned name should be qualified with the name(s) of the enclosing
      *            class/classes of {@code clazz} (if any). This option is ignored if {@code clazz} denotes an anonymous
@@ -84,7 +91,7 @@
     /**
      * Converts a given type to its Java programming language name. The following are examples of strings returned by
      * this method:
-     * 
+     *
      * <pre>
      *     qualified == true:
      *         java.lang.Object
@@ -95,7 +102,7 @@
      *         int
      *         boolean[][]
      * </pre>
-     * 
+     *
      * @param type the type to be converted to a Java name
      * @param qualified specifies if the package prefix of the type should be included in the returned name
      * @return the Java name corresponding to {@code type}
@@ -111,13 +118,13 @@
     /**
      * Converts a given type to its Java programming language name. The following are examples of strings returned by
      * this method:
-     * 
+     *
      * <pre>
      *      java.lang.Object
      *      int
      *      boolean[][]
      * </pre>
-     * 
+     *
      * @param type the type to be converted to a Java name
      * @return the Java name corresponding to {@code type}
      */
@@ -153,7 +160,7 @@
      * composed of characters that are to be copied verbatim to the result and specifiers that denote an attribute of
      * the method that is to be copied to the result. A specifier is a single character preceded by a '%' character. The
      * accepted specifiers and the method attributes they denote are described below:
-     * 
+     *
      * <pre>
      *     Specifier | Description                                          | Example(s)
      *     ----------+------------------------------------------------------------------------------------------
@@ -167,7 +174,7 @@
      *     'f'       | Indicator if method is unresolved, static or virtual | "unresolved" "static" "virtual"
      *     '%'       | A '%' character                                      | "%"
      * </pre>
-     * 
+     *
      * @param format a format specification
      * @param method the method to be formatted
      * @return the result of formatting this method according to {@code format}
@@ -246,7 +253,7 @@
      * composed of characters that are to be copied verbatim to the result and specifiers that denote an attribute of
      * the field that is to be copied to the result. A specifier is a single character preceded by a '%' character. The
      * accepted specifiers and the field attributes they denote are described below:
-     * 
+     *
      * <pre>
      *     Specifier | Description                                          | Example(s)
      *     ----------+------------------------------------------------------------------------------------------
@@ -258,7 +265,7 @@
      *     'f'       | Indicator if field is unresolved, static or instance | "unresolved" "static" "instance"
      *     '%'       | A '%' character                                      | "%"
      * </pre>
-     * 
+     *
      * @param format a format specification
      * @param field the field to be formatted
      * @return the result of formatting this field according to {@code format}
@@ -316,7 +323,7 @@
 
     /**
      * Gets the annotations of a particular type for the formal parameters of a given method.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @param method the method for which a parameter annotations are being requested
      * @return the annotation of type {@code annotationClass} (if any) for each formal parameter present
@@ -337,7 +344,7 @@
 
     /**
      * Gets the annotation of a particular type for a formal parameter of a given method.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @param parameterIndex the index of a formal parameter of {@code method}
      * @param method the method for which a parameter annotation is being requested
@@ -370,18 +377,18 @@
      * {@linkplain ResolvedJavaMethod#asStackTraceElement(int) available} for the given method, then the string returned
      * is the {@link StackTraceElement#toString()} value of the stack trace element, suffixed by the bci location. For
      * example:
-     * 
+     *
      * <pre>
      *     java.lang.String.valueOf(String.java:2930) [bci: 12]
      * </pre>
-     * 
+     *
      * Otherwise, the string returned is the value of applying {@link #format(String, JavaMethod)} with the format
      * string {@code "%H.%n(%p)"}, suffixed by the bci location. For example:
-     * 
+     *
      * <pre>
      *     java.lang.String.valueOf(int) [bci: 12]
      * </pre>
-     * 
+     *
      * @param sb
      * @param method
      * @param bci
@@ -433,7 +440,7 @@
 
     /**
      * Formats some profiling information associated as a string.
-     * 
+     *
      * @param info the profiling info to format
      * @param method an optional method that augments the profile string returned
      * @param sep the separator to use for each separate profile record
@@ -500,12 +507,46 @@
 
     /**
      * Converts a Java source-language class name into the internal form.
-     * 
+     *
      * @param className the class name
      * @return the internal name form of the class name
      */
     public static String toInternalName(String className) {
-        return "L" + className.replace('.', '/') + ";";
+        String prefix = "";
+        String base = className;
+        while (base.endsWith("[]")) {
+            prefix += "[";
+            base = base.substring(base.length() - 2);
+        }
+
+        if (className.equals("boolean")) {
+            return prefix + "Z";
+        }
+        if (className.equals("byte")) {
+            return prefix + "B";
+        }
+        if (className.equals("short")) {
+            return prefix + "S";
+        }
+        if (className.equals("char")) {
+            return prefix + "C";
+        }
+        if (className.equals("int")) {
+            return prefix + "I";
+        }
+        if (className.equals("float")) {
+            return prefix + "F";
+        }
+        if (className.equals("long")) {
+            return prefix + "J";
+        }
+        if (className.equals("double")) {
+            return prefix + "D";
+        }
+        if (className.equals("void")) {
+            return prefix + "V";
+        }
+        return prefix + "L" + className.replace('.', '/') + ";";
     }
 
     /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Mon Nov 26 10:57:02 2012 +0100
@@ -155,7 +155,8 @@
     ResolvedJavaType getSuperclass();
 
     /**
-     * Gets the interfaces that this type defines. This method is analogous to {@link Class#getInterfaces()}.
+     * Gets the interfaces implemented or extended by this type. This method is analogous to {@link Class#getInterfaces()}
+     * and as such, only returns the interfaces directly implemented or extended by this type.
      */
     ResolvedJavaType[] getInterfaces();
 
@@ -223,6 +224,11 @@
     <T extends Annotation> T getAnnotation(Class<T> annotationClass);
 
     /**
+     * Determines if this type is the same as that represented by a given {@link Class}.
+     */
+    boolean isClass(Class c);
+
+    /**
      * Returns the {@link java.lang.Class} object representing this type.
      */
     Class< ? > toJava();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Mon Nov 26 10:57:02 2012 +0100
@@ -22,18 +22,18 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import junit.framework.Assert;
+import junit.framework.*;
 
 import org.junit.Test;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
@@ -44,46 +44,42 @@
 
     @Test
     public void test1() {
-        test("test1Snippet", Constant.forInt(101));
+        testEscapeAnalysis("test1Snippet", Constant.forInt(101), false);
     }
 
-    @SuppressWarnings("all")
-    public static int test1Snippet(int a) {
+    public static int test1Snippet() {
         Integer x = new Integer(101);
         return x.intValue();
     }
 
     @Test
     public void test2() {
-        test("test2Snippet", Constant.forInt(0));
+        testEscapeAnalysis("test2Snippet", Constant.forInt(0), false);
     }
 
-    @SuppressWarnings("all")
-    public static int test2Snippet(int a) {
+    public static int test2Snippet() {
         Integer[] x = new Integer[0];
         return x.length;
     }
 
     @Test
     public void test3() {
-        test("test3Snippet", Constant.forObject(null));
+        testEscapeAnalysis("test3Snippet", Constant.forObject(null), false);
     }
 
-    @SuppressWarnings("all")
-    public static Object test3Snippet(int a) {
+    public static Object test3Snippet() {
         Integer[] x = new Integer[1];
         return x[0];
     }
 
     @Test
     public void testMonitor() {
-        test("testMonitorSnippet", Constant.forInt(0));
+        testEscapeAnalysis("testMonitorSnippet", Constant.forInt(0), false);
     }
 
     private static native void notInlineable();
 
-    @SuppressWarnings("all")
-    public static int testMonitorSnippet(int a) {
+    public static int testMonitorSnippet() {
         Integer x = new Integer(0);
         Integer[] y = new Integer[0];
         Integer[] z = new Integer[1];
@@ -99,14 +95,13 @@
 
     @Test
     public void testMonitor2() {
-        test("testMonitor2Snippet", Constant.forInt(0));
+        testEscapeAnalysis("testMonitor2Snippet", Constant.forInt(0), false);
     }
 
     /**
      * This test case differs from the last one in that it requires inlining within a synchronized region.
      */
-    @SuppressWarnings("all")
-    public static int testMonitor2Snippet(int a) {
+    public static int testMonitor2Snippet() {
         Integer x = new Integer(0);
         Integer[] y = new Integer[0];
         Integer[] z = new Integer[1];
@@ -122,7 +117,7 @@
 
     @Test
     public void testMerge() {
-        test("testMerge1Snippet", Constant.forInt(0));
+        testEscapeAnalysis("testMerge1Snippet", Constant.forInt(0), true);
     }
 
     public static class TestObject {
@@ -150,7 +145,7 @@
 
     @Test
     public void testSimpleLoop() {
-        test("testSimpleLoopSnippet", Constant.forInt(1));
+        testEscapeAnalysis("testSimpleLoopSnippet", Constant.forInt(1), false);
     }
 
     public int testSimpleLoopSnippet(int a) {
@@ -161,38 +156,60 @@
         return obj.x;
     }
 
-    private void test(final String snippet, final Constant expectedResult) {
-        Debug.scope("EscapeAnalysisTest", new DebugDumpScope(snippet), new Runnable() {
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                for (Invoke n : graph.getInvokes()) {
-                    n.node().setProbability(100000);
-                }
+    public static class TestObject2 {
+        Object o;
+        public TestObject2(Object o) {
+            this.o = o;
+        }
+    }
+
+    @Test
+    public void testCheckCast() {
+        testEscapeAnalysis("testCheckCastSnippet", Constant.forObject(TestObject2.class), false);
+    }
+
+    public Object testCheckCastSnippet() {
+        TestObject2 obj = new TestObject2(TestObject2.class);
+        TestObject2 obj2 = new TestObject2(obj);
+        return ((TestObject2) obj2.o).o;
+    }
+
+    @Test
+    public void testInstanceOf() {
+        ReturnNode returnNode = testEscapeAnalysis("testInstanceOfSnippet", null, false);
+        ValueNode result = returnNode.result();
+        Assert.assertTrue(result instanceof MaterializeNode);
+        Assert.assertEquals(Constant.TRUE, ((MaterializeNode) result).condition().asConstant());
+    }
 
-                Assumptions assumptions = new Assumptions(false);
-                new InliningPhase(null, runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-                Debug.dump(graph, "Graph");
-                new PartialEscapeAnalysisPhase(null, runtime(), assumptions).apply(graph);
-                new CullFrameStatesPhase().apply(graph);
-                new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
-                Debug.dump(graph, "Graph");
-                int retCount = 0;
-                for (ReturnNode ret : graph.getNodes(ReturnNode.class)) {
-                    Assert.assertTrue(ret.result().isConstant());
-                    Assert.assertEquals(ret.result().asConstant(), expectedResult);
-                    retCount++;
-                }
-                Assert.assertEquals(1, retCount);
-                int newInstanceCount = 0;
-                for (@SuppressWarnings("unused") NewInstanceNode n : graph.getNodes(NewInstanceNode.class)) {
-                    newInstanceCount++;
-                }
-                for (@SuppressWarnings("unused") NewObjectArrayNode n : graph.getNodes(NewObjectArrayNode.class)) {
-                    newInstanceCount++;
-                }
-                Assert.assertEquals(0, newInstanceCount);
+    public boolean testInstanceOfSnippet() {
+        TestObject2 obj = new TestObject2(TestObject2.class);
+        TestObject2 obj2 = new TestObject2(obj);
+        return obj2.o instanceof TestObject2;
+    }
+
+    private ReturnNode testEscapeAnalysis(String snippet, Constant expectedConstantResult, boolean iterativeEscapeAnalysis) {
+        StructuredGraph graph = parse(snippet);
+        try {
+            for (Invoke n : graph.getInvokes()) {
+                n.node().setProbability(100000);
             }
-        });
+
+            Assumptions assumptions = new Assumptions(false);
+            new InliningPhase(null, runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
+            new DeadCodeEliminationPhase().apply(graph);
+            new PartialEscapeAnalysisPhase(null, runtime(), null, assumptions, iterativeEscapeAnalysis).apply(graph);
+            Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
+            ReturnNode returnNode = graph.getNodes(ReturnNode.class).first();
+            if (expectedConstantResult != null) {
+                Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
+                Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
+            }
+            int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewObjectArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count();
+            Assert.assertEquals(0, newInstanceCount);
+            return returnNode;
+        } catch (AssertionFailedError t) {
+            throw new RuntimeException(t.getMessage() + "\n" + getCanonicalGraphString(graph), t);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon Nov 26 10:57:02 2012 +0100
@@ -22,15 +22,13 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import java.util.concurrent.*;
-
+import junit.framework.*;
 import junit.framework.Assert;
 
 import org.junit.Test;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -146,27 +144,24 @@
     }
 
     private StructuredGraph processMethod(final String snippet) {
-        return Debug.scope(getClass().getSimpleName(), new Callable<StructuredGraph>() {
-            @Override
-            public StructuredGraph call() throws Exception {
-                StructuredGraph graph = parse(snippet);
-                new ComputeProbabilityPhase().apply(graph);
-                for (Invoke n : graph.getInvokes()) {
-                    n.node().setProbability(100000);
-                }
-                Assumptions assumptions = new Assumptions(false);
-                new InliningPhase(null, runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-                new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
-//                TypeSystemTest.outputGraph(graph, "before EscapeAnalysis " + snippet);
-                new PartialEscapeAnalysisPhase(null, runtime(), assumptions).apply(graph);
-//                TypeSystemTest.outputGraph(graph, "after EscapeAnalysis " + snippet);
-                new CullFrameStatesPhase().apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-                new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
-//                TypeSystemTest.outputGraph(graph, "after CullFrameStates " + snippet);
-                return graph;
+        StructuredGraph graph = parse(snippet);
+        try {
+            new ComputeProbabilityPhase().apply(graph);
+            for (Invoke n : graph.getInvokes()) {
+                n.node().setProbability(100000);
             }
-        });
+            Assumptions assumptions = new Assumptions(false);
+            new InliningPhase(null, runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
+            new DeadCodeEliminationPhase().apply(graph);
+            new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
+            new PartialEscapeAnalysisPhase(null, runtime(), null, assumptions, false).apply(graph);
+
+            new CullFrameStatesPhase().apply(graph);
+            new DeadCodeEliminationPhase().apply(graph);
+            new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
+            return graph;
+        } catch (AssertionFailedError t) {
+            throw new RuntimeException(t.getMessage() + "\n" + getCanonicalGraphString(graph), t);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Nov 26 10:57:02 2012 +0100
@@ -149,7 +149,7 @@
         }
 
         if (GraalOptions.PartialEscapeAnalysis && !plan.isPhaseDisabled(PartialEscapeAnalysisPhase.class)) {
-            new PartialEscapeAnalysisPhase(target, runtime, assumptions).apply(graph);
+            new PartialEscapeAnalysisPhase(target, runtime, assumptions, true).apply(graph);
         }
         if (GraalOptions.OptLoopTransform) {
             new LoopTransformHighPhase().apply(graph);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon Nov 26 10:57:02 2012 +0100
@@ -119,9 +119,6 @@
             printConfig(config);
         }
 
-        AddressMap.log(config.cardtableStartAddress, "CARDTABLE");
-        AddressMap.log(config.cardtableStartAddress, "SAFEPOINT_POLL_PAGE");
-
         target = createTarget();
         assert wordKind == null || wordKind.equals(target.wordKind);
         wordKind = target.wordKind;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Nov 26 10:57:02 2012 +0100
@@ -143,13 +143,6 @@
 
     JavaType getUniqueConcreteSubtype(HotSpotResolvedJavaType klass);
 
-    int getArrayLength(Constant array);
-
-    /**
-     * Gets the type of an object constant.
-     */
-    JavaType getJavaType(Constant constant);
-
     HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedJavaType klass);
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Nov 26 10:57:02 2012 +0100
@@ -113,20 +113,6 @@
     public native ResolvedJavaType getResolvedType(Class<?> javaClass);
 
     @Override
-    public int getArrayLength(Constant array) {
-        return Array.getLength(array.asObject());
-    }
-
-    @Override
-    public JavaType getJavaType(Constant constant) {
-        Object o = constant.asObject();
-        if (o == null) {
-            return null;
-        }
-        return HotSpotResolvedJavaType.fromClass(o.getClass());
-    }
-
-    @Override
     public native HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedJavaType klass);
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Nov 26 10:57:02 2012 +0100
@@ -527,7 +527,6 @@
             // lost the race - return the existing value instead
             type = (HotSpotResolvedJavaType) unsafe.getObject(javaMirror, offset);
         }
-        AddressMap.log(metaspaceKlass, type.toJava().getName());
         return type;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/AddressMap.java	Mon Nov 26 10:51:39 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 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.hotspot.meta;
-
-import java.io.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.phases.*;
-
-/**
- * Utility for logging an address to symbol mapping to a file.
- * This is useful when looking at disassembled code.
- *
- * @see GraalOptions#PrintAddressMap
- */
-public class AddressMap {
-
-    private static PrintStream addressMapStream;
-    static {
-        synchronized (AddressMap.class) {
-            if (GraalOptions.PrintAddressMap) {
-                File file = new File("addressMap-" + System.currentTimeMillis() + ".log");
-                try {
-                    addressMapStream = new PrintStream(new FileOutputStream(file), true);
-                } catch (FileNotFoundException e) {
-                    throw new GraalInternalError("Could not open " + file.getAbsolutePath());
-                }
-                TTY.println("Logging {address -> symbol} map to %s", file);
-            }
-        }
-    }
-
-    public static void log(long address, String symbol) {
-        if (addressMapStream != null) {
-            synchronized (addressMapStream) {
-                addressMapStream.println("0x" + Long.toHexString(address) + " " + symbol);
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Nov 26 10:57:02 2012 +0100
@@ -63,7 +63,6 @@
         this.metaspaceMethod = metaspaceMethod;
         this.holder = holder;
         HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeMethod(metaspaceMethod, this);
-        AddressMap.log(metaspaceMethod, MetaUtil.format("%H.%n(%P):%R", this));
     }
 
     @Override
@@ -203,7 +202,6 @@
             long metaspaceMethodData = unsafe.getLong(null, metaspaceMethod + HotSpotGraalRuntime.getInstance().getConfig().methodDataOffset);
             if (metaspaceMethodData != 0) {
                 methodData = new HotSpotMethodData(metaspaceMethodData);
-                AddressMap.log(metaspaceMethodData, MetaUtil.format("MethodData{%H.%n(%P):%R}", this));
             }
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Mon Nov 26 10:57:02 2012 +0100
@@ -254,7 +254,10 @@
 
     @Override
     public boolean isInstance(Constant obj) {
-        return javaMirror.isInstance(obj);
+        if (obj.getKind().isObject() && !obj.isNull()) {
+            return javaMirror.isInstance(obj.asObject());
+        }
+        return false;
     }
 
     @Override
@@ -392,6 +395,11 @@
     }
 
     @Override
+    public boolean isClass(Class c) {
+        return c == javaMirror;
+    }
+
+    @Override
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
         return javaMirror.getAnnotation(annotationClass);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Nov 26 10:57:02 2012 +0100
@@ -330,7 +330,11 @@
 
     @Override
     public ResolvedJavaType lookupJavaType(Constant constant) {
-        return (ResolvedJavaType) graalRuntime.getCompilerToVM().getJavaType(constant);
+        if (!constant.getKind().isObject() || constant.isNull()) {
+            return null;
+        }
+        Object o = constant.asObject();
+        return HotSpotResolvedJavaType.fromClass(o.getClass());
     }
 
     @Override
@@ -363,7 +367,10 @@
 
     @Override
     public int lookupArrayLength(Constant array) {
-        return graalRuntime.getCompilerToVM().getArrayLength(array);
+        if (!array.getKind().isObject() || array.isNull() || !array.asObject().getClass().isArray()) {
+            throw new IllegalArgumentException(array + " is not an array");
+        }
+        return Array.getLength(array.asObject());
     }
 
     @Override
@@ -388,7 +395,7 @@
                 AbstractCallTargetNode loweredCallTarget = null;
                 if (callTarget.invokeKind() == InvokeKind.Virtual &&
                     GraalOptions.InlineVTableStubs &&
-                    (GraalOptions.AlwaysInlineVTableStubs || invoke.isMegamorphic())) {
+                    (GraalOptions.AlwaysInlineVTableStubs || invoke.isPolymorphic())) {
 
                     HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
                     if (!hsMethod.getDeclaringClass().isInterface()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java	Mon Nov 26 10:57:02 2012 +0100
@@ -167,6 +167,11 @@
     }
 
     @Override
+    public boolean isClass(Class c) {
+        return c == javaMirror;
+    }
+
+    @Override
     public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
         return this;
     }
--- a/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java	Mon Nov 26 10:57:02 2012 +0100
@@ -1207,7 +1207,7 @@
     }
 
     private void instanceOf(InterpreterFrame frame, char cpi) {
-        frame.pushInt(resolveType(frame, Bytecodes.INSTANCEOF, cpi).toJava().isInstance(frame.popObject()) ? 1 : 0);
+        frame.pushInt(resolveType(frame, Bytecodes.INSTANCEOF, cpi).isInstance(Constant.forObject(frame.popObject())) ? 1 : 0);
     }
 
     private void pushCPConstant(InterpreterFrame frame, char cpi) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Mon Nov 26 10:57:02 2012 +0100
@@ -62,11 +62,11 @@
     void setUseForInlining(boolean value);
 
     /**
-     * True if this invocation is almost certainly megamorphic, false when in doubt.
+     * True if this invocation is almost certainly polymorphic, false when in doubt.
      */
-    boolean isMegamorphic();
+    boolean isPolymorphic();
 
-    void setMegamorphic(boolean value);
+    void setPolymorphic(boolean value);
 
     long leafGraphId();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Nov 26 10:57:02 2012 +0100
@@ -39,7 +39,7 @@
 
     @Input private final CallTargetNode callTarget;
     private final int bci;
-    private boolean megamorphic;
+    private boolean polymorphic;
     private boolean useForInlining;
     private final long leafGraphId;
 
@@ -54,7 +54,7 @@
         this.callTarget = callTarget;
         this.bci = bci;
         this.leafGraphId = leafGraphId;
-        this.megamorphic = false;
+        this.polymorphic = false;
         this.useForInlining = true;
     }
 
@@ -69,13 +69,13 @@
     }
 
     @Override
-    public boolean isMegamorphic() {
-        return megamorphic;
+    public boolean isPolymorphic() {
+        return polymorphic;
     }
 
     @Override
-    public void setMegamorphic(boolean value) {
-        this.megamorphic = value;
+    public void setPolymorphic(boolean value) {
+        this.polymorphic = value;
     }
 
     public boolean useForInlining() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Nov 26 10:57:02 2012 +0100
@@ -39,8 +39,7 @@
     @Input private final CallTargetNode callTarget;
     @Input private FrameState stateAfter;
     private final int bci;
-    // megamorph should only be true when the compiler is sure that the call site is megamorph, and false when in doubt
-    private boolean megamorphic;
+    private boolean polymorphic;
     private boolean useForInlining;
     private final long leafGraphId;
 
@@ -49,7 +48,7 @@
         this.bci = bci;
         this.callTarget = callTarget;
         this.leafGraphId = leafGraphId;
-        this.megamorphic = true;
+        this.polymorphic = false;
         this.useForInlining = true;
     }
 
@@ -78,13 +77,13 @@
     }
 
     @Override
-    public boolean isMegamorphic() {
-        return megamorphic;
+    public boolean isPolymorphic() {
+        return polymorphic;
     }
 
     @Override
-    public void setMegamorphic(boolean value) {
-        this.megamorphic = value;
+    public void setPolymorphic(boolean value) {
+        this.polymorphic = value;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java	Mon Nov 26 10:57:02 2012 +0100
@@ -133,7 +133,7 @@
         if (boxing == null) {
             return false;
         }
-        return method.getDeclaringClass().toJava() == boxing.type && method.getName().equals("valueOf");
+        return method.getDeclaringClass().isClass(boxing.type) && method.getName().equals("valueOf");
     }
 
     public static boolean isUnboxingMethodStatic(ResolvedJavaMethod method) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon Nov 26 10:57:02 2012 +0100
@@ -28,11 +28,12 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, LIRLowerable {
+public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, LIRLowerable, Virtualizable {
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
@@ -129,4 +130,12 @@
         }
         return super.verify();
     }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        VirtualObjectNode virtual = tool.getVirtualState(object());
+        if (virtual != null) {
+            tool.replaceWithValue(ConstantNode.forBoolean(virtual.type().isSubtypeOf(type()), graph()));
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Nov 26 10:57:02 2012 +0100
@@ -105,32 +105,17 @@
     }
 
     @Override
-    public EscapeOp getEscapeOp() {
+    public ObjectDesc[] getAllocations(long nextVirtualId, MetaAccessProvider metaAccess) {
         if (length().asConstant() != null) {
             final int constantLength = length().asConstant().asInt();
             if (constantLength >= 0 && constantLength < MaximumEscapeAnalysisArrayLength) {
-                return new EscapeOp() {
-
-                    @Override
-                    public ValueNode[] fieldState() {
-                        ValueNode[] state = new ValueNode[constantLength];
-                        ConstantNode defaultForKind = constantLength == 0 ? null : ConstantNode.defaultForKind(elementType().getKind(), graph());
-                        for (int i = 0; i < constantLength; i++) {
-                            state[i] = defaultForKind;
-                        }
-                        return state;
-                    }
-
-                    @Override
-                    public VirtualObjectNode virtualObject(long virtualId) {
-                        return new VirtualArrayNode(virtualId, elementType, constantLength);
-                    }
-
-                    @Override
-                    public int lockCount() {
-                        return 0;
-                    }
-                };
+                ValueNode[] state = new ValueNode[constantLength];
+                ConstantNode defaultForKind = constantLength == 0 ? null : ConstantNode.defaultForKind(elementType().getKind(), graph());
+                for (int i = 0; i < constantLength; i++) {
+                    state[i] = defaultForKind;
+                }
+                VirtualObjectNode virtualObject = new VirtualArrayNode(nextVirtualId, elementType, constantLength);
+                return new ObjectDesc[]{new ObjectDesc(virtualObject, state, 0)};
             }
         }
         return null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Nov 26 10:57:02 2012 +0100
@@ -82,31 +82,16 @@
     }
 
     @Override
-    public EscapeOp getEscapeOp() {
+    public ObjectDesc[] getAllocations(long nextVirtualId, MetaAccessProvider metaAccess) {
         if (instanceClass != null) {
             assert !instanceClass().isArrayClass();
-            final ResolvedJavaField[] fields = instanceClass().getInstanceFields(true);
-            return new EscapeOp() {
-
-                @Override
-                public ValueNode[] fieldState() {
-                    ValueNode[] state = new ValueNode[fields.length];
-                    for (int i = 0; i < state.length; i++) {
-                        state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph());
-                    }
-                    return state;
-                }
-
-                @Override
-                public VirtualObjectNode virtualObject(long virtualId) {
-                    return new VirtualInstanceNode(virtualId, instanceClass(), fields);
-                }
-
-                @Override
-                public int lockCount() {
-                    return 0;
-                }
-            };
+            ResolvedJavaField[] fields = instanceClass().getInstanceFields(true);
+            ValueNode[] state = new ValueNode[fields.length];
+            for (int i = 0; i < state.length; i++) {
+                state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph());
+            }
+            VirtualObjectNode virtualObject = new VirtualInstanceNode(nextVirtualId, instanceClass(), fields);
+            return new ObjectDesc[]{new ObjectDesc(virtualObject, state, 0)};
         }
         return null;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeAnalyzable.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeAnalyzable.java	Mon Nov 26 10:57:02 2012 +0100
@@ -22,7 +22,24 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.virtual.*;
+
 public interface EscapeAnalyzable {
 
-    EscapeOp getEscapeOp();
+    public static class ObjectDesc {
+
+        public final VirtualObjectNode virtualObject;
+        public final ValueNode[] entryState;
+        public final int lockCount;
+
+        public ObjectDesc(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount) {
+            this.virtualObject = virtualObject;
+            this.entryState = entryState;
+            this.lockCount = lockCount;
+        }
+    }
+
+    ObjectDesc[] getAllocations(long nextVirtualId, MetaAccessProvider metaAccess);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Mon Nov 26 10:51:39 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 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.nodes.spi;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.virtual.*;
-
-public abstract class EscapeOp {
-
-    /**
-     * Returns the initial value of all fields.
-     */
-    public abstract ValueNode[] fieldState();
-
-    public abstract VirtualObjectNode virtualObject(long virtualId);
-
-    public abstract int lockCount();
-
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Nov 26 10:57:02 2012 +0100
@@ -1,1004 +1,1000 @@
-/*
- * Copyright (c) 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.phases.common;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.concurrent.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-
-public class InliningUtil {
-    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
-    private static final String inliningDecisionsScopeString = "InliningDecisions";
-
-    public interface InliningCallback {
-        StructuredGraph buildGraph(final ResolvedJavaMethod method);
-    }
-
-    public interface InliningPolicy {
-        void initialize(StructuredGraph graph);
-        boolean continueInlining(StructuredGraph graph);
-        InlineInfo next();
-        void scanInvokes(Iterable<? extends Node> newNodes);
-        double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke);
-        boolean isWorthInlining(InlineInfo info);
-    }
-
-    public interface WeightComputationPolicy {
-        double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke);
-    }
-
-    public static void logNotInlinedMethod(InlineInfo info, String msg, Object... args) {
-        logInliningDecision(info, false, msg, args);
-    }
-
-    public static void logInliningDecision(InlineInfo info, boolean success, String msg, final Object... args) {
-        if (shouldLogInliningDecision()) {
-            logInliningDecision(methodName(info), success, msg, args);
-        }
-    }
-
-    public static void logInliningDecision(final String msg, final Object... args) {
-        Debug.scope(inliningDecisionsScopeString, new Runnable() {
-            public void run() {
-                Debug.log(msg, args);
-            }
-        });
-    }
-
-    private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, String msg) {
-        if (shouldLogInliningDecision()) {
-            String methodString = invoke.callTarget() == null ? "callTarget=null" : invoke.callTarget().targetName();
-            logInliningDecision(methodString, false, msg, new Object[0]);
-        }
-        return false;
-    }
-
-    private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, ResolvedJavaMethod method, String msg) {
-        if (shouldLogInliningDecision()) {
-            String methodString = methodName(method, invoke);
-            logInliningDecision(methodString, false, msg, new Object[0]);
-        }
-        return null;
-    }
-
-    private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, ResolvedJavaMethod method, String msg) {
-        if (shouldLogInliningDecision()) {
-            String methodString = methodName(method, invoke);
-            logInliningDecision(methodString, false, msg, new Object[0]);
-        }
-        return false;
-    }
-
-    private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
-        String inliningMsg = "inlining " + methodString + ": " + msg;
-        if (!success) {
-            inliningMsg = "not " + inliningMsg;
-        }
-        logInliningDecision(inliningMsg, args);
-    }
-
-    private static boolean shouldLogInliningDecision() {
-        return Debug.scope(inliningDecisionsScopeString, new Callable<Boolean>() {
-            public Boolean call() {
-                return Debug.isLogEnabled();
-            }
-        });
-    }
-
-    private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
-        if (invoke != null && invoke.stateAfter() != null) {
-            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
-        } else {
-            return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
-        }
-    }
-
-    private static String methodName(InlineInfo info) {
-        if (info == null) {
-            return "null";
-        } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
-            return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
-        } else {
-            return info.toString();
-        }
-    }
-
-    private static String methodName(FrameState frameState, int bci) {
-        StringBuilder sb = new StringBuilder();
-        if (frameState.outerFrameState() != null) {
-            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
-            sb.append("->");
-        }
-        sb.append(MetaUtil.format("%h.%n", frameState.method()));
-        sb.append("@").append(bci);
-        return sb.toString();
-    }
-
-    /**
-     * Represents an opportunity for inlining at the given invoke, with the given weight and level.
-     * The weight is the amortized weight of the additional code - so smaller is better.
-     * The level is the number of nested inlinings that lead to this invoke.
-     */
-    public interface InlineInfo extends Comparable<InlineInfo> {
-        Invoke invoke();
-        double weight();
-        int level();
-        int compiledCodeSize();
-        int compareTo(InlineInfo o);
-
-        /**
-         * Performs the inlining described by this object and returns the node that represents the return value of the
-         * inlined method (or null for void methods and methods that have no non-exceptional exit).
-         */
-        void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions);
-    }
-
-    public abstract static class AbstractInlineInfo implements InlineInfo {
-        protected final Invoke invoke;
-        protected final double weight;
-
-        public AbstractInlineInfo(Invoke invoke, double weight) {
-            this.invoke = invoke;
-            this.weight = weight;
-        }
-
-        @Override
-        public int compareTo(InlineInfo o) {
-            return (weight < o.weight()) ? -1 : (weight > o.weight()) ? 1 : 0;
-        }
-
-        public Invoke invoke() {
-            return invoke;
-        }
-
-        public double weight() {
-            return weight;
-        }
-
-        public int level() {
-            return computeInliningLevel(invoke);
-        }
-
-        protected static StructuredGraph getGraph(final Invoke invoke, final ResolvedJavaMethod concrete, final GraalCodeCacheProvider runtime, final InliningCallback callback) {
-            return Debug.scope("GetInliningGraph", concrete, new Callable<StructuredGraph>() {
-                @Override
-                public StructuredGraph call() throws Exception {
-                    StructuredGraph result = getIntrinsicGraph(invoke, concrete, runtime);
-                    if (result == null) {
-                        assert !Modifier.isNative(concrete.getModifiers());
-                        result = callback.buildGraph(concrete);
-                    }
-                    return result;
-                }
-            });
-        }
-    }
-
-    /**
-     * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and
-     * therefore is able to determine the called method exactly.
-     */
-    private static class ExactInlineInfo extends AbstractInlineInfo {
-        public final ResolvedJavaMethod concrete;
-
-        public ExactInlineInfo(Invoke invoke, double weight, ResolvedJavaMethod concrete) {
-            super(invoke, weight);
-            this.concrete = concrete;
-        }
-
-        @Override
-        public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            StructuredGraph graph = getGraph(invoke, concrete, runtime, callback);
-            assumptions.recordMethodContents(concrete);
-            InliningUtil.inline(invoke, graph, true);
-        }
-
-        @Override
-        public int compiledCodeSize() {
-            return concrete.getCompiledCodeSize();
-        }
-
-        @Override
-        public String toString() {
-            return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-    }
-
-    /**
-     * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which
-     * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed.
-     */
-    private static class TypeGuardInlineInfo extends AbstractInlineInfo {
-        public final ResolvedJavaMethod concrete;
-        public final ResolvedJavaType type;
-
-        public TypeGuardInlineInfo(Invoke invoke, double weight, ResolvedJavaMethod concrete, ResolvedJavaType type) {
-            super(invoke, weight);
-            this.concrete = concrete;
-            this.type = type;
-        }
-
-        @Override
-        public int compiledCodeSize() {
-            return concrete.getCompiledCodeSize();
-        }
-
-        @Override
-        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            // receiver null check must be before the type check
-            InliningUtil.receiverNullCheck(invoke);
-            ValueNode receiver = invoke.methodCallTarget().receiver();
-            ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), runtime, graph);
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(receiver, typeHub.kind()));
-            CompareNode typeCheck = CompareNode.createCompareNode(Condition.EQ, receiverHub, typeHub);
-            FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId()));
-            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
-            assert invoke.predecessor() != null;
-
-            ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true);
-            invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
-            graph.addBeforeFixed(invoke.node(), receiverHub);
-            graph.addBeforeFixed(invoke.node(), guard);
-            graph.addBeforeFixed(invoke.node(), anchor);
-
-            StructuredGraph calleeGraph = getGraph(invoke, concrete, runtime, callback);
-            assumptions.recordMethodContents(concrete);
-            InliningUtil.inline(invoke, calleeGraph, false);
-        }
-
-        @Override
-        public String toString() {
-            return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-    }
-
-    /**
-     * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable
-     * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered.
-     */
-    private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
-        public final List<ResolvedJavaMethod> concretes;
-        public final ProfiledType[] ptypes;
-        public final int[] typesToConcretes;
-        public final double notRecordedTypeProbability;
-
-        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, List<ResolvedJavaMethod> concretes, ProfiledType[] ptypes,
-                        int[] typesToConcretes, double notRecordedTypeProbability) {
-            super(invoke, weight);
-            assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods";
-            assert ptypes.length == typesToConcretes.length : "array lengths must match";
-
-            this.concretes = concretes;
-            this.ptypes = ptypes;
-            this.typesToConcretes = typesToConcretes;
-            this.notRecordedTypeProbability = notRecordedTypeProbability;
-        }
-
-        @Override
-        public int compiledCodeSize() {
-            int result = 0;
-            for (ResolvedJavaMethod m: concretes) {
-                result += m.getCompiledCodeSize();
-            }
-            return result;
-        }
-
-        @Override
-        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            int numberOfMethods = concretes.size();
-            boolean hasReturnValue = invoke.node().kind() != Kind.Void;
-
-            // receiver null check must be the first node
-            InliningUtil.receiverNullCheck(invoke);
-            if (numberOfMethods > 1 || shouldFallbackToInvoke()) {
-                inlineMultipleMethods(graph, runtime, callback, assumptions, numberOfMethods, hasReturnValue);
-            } else {
-                inlineSingleMethod(graph, runtime, callback, assumptions);
-            }
-        }
-
-        private boolean shouldFallbackToInvoke() {
-            return notRecordedTypeProbability > 0;
-        }
-
-        private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions, int numberOfMethods, boolean hasReturnValue) {
-            FixedNode continuation = invoke.next();
-
-            ValueNode originalReceiver = invoke.methodCallTarget().receiver();
-            // setup merge and phi nodes for results and exceptions
-            MergeNode returnMerge = graph.add(new MergeNode());
-            returnMerge.setProbability(invoke.probability());
-            returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci));
-
-            PhiNode returnValuePhi = null;
-            if (hasReturnValue) {
-                returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge));
-            }
-
-            MergeNode exceptionMerge = null;
-            PhiNode exceptionObjectPhi = null;
-            if (invoke instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge();
-                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
-
-                exceptionMerge = graph.add(new MergeNode());
-                exceptionMerge.setProbability(exceptionEdge.probability());
-
-                FixedNode exceptionSux = exceptionObject.next();
-                graph.addBeforeFixed(exceptionSux, exceptionMerge);
-                exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge));
-                exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi));
-            }
-
-            // create one separate block for each invoked method
-            BeginNode[] successors = new BeginNode[numberOfMethods + 1];
-            for (int i = 0; i < numberOfMethods; i++) {
-                double probability = 0;
-                for (int j = 0; j < typesToConcretes.length; j++) {
-                    if (typesToConcretes[j] == i) {
-                        probability += ptypes[j].getProbability();
-                    }
-                }
-
-                successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, invoke.probability() * probability, true);
-            }
-
-            // create the successor for an unknown type
-            FixedNode unknownTypeSux;
-            if (shouldFallbackToInvoke()) {
-                unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, notRecordedTypeProbability, false);
-            } else {
-                unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId()));
-            }
-            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
-
-            // replace the invoke exception edge
-            if (invoke instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
-                BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge();
-                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
-                exceptionObject.replaceAtUsages(exceptionObjectPhi);
-                exceptionObject.setNext(null);
-                GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
-            }
-
-            // get all graphs and record assumptions
-            assert invoke.node().isAlive();
-            StructuredGraph[] calleeGraphs = new StructuredGraph[numberOfMethods];
-            for (int i = 0; i < numberOfMethods; i++) {
-                ResolvedJavaMethod concrete = concretes.get(i);
-                calleeGraphs[i] = getGraph(invoke, concrete, runtime, callback);
-                assumptions.recordMethodContents(concrete);
-            }
-
-            // replace the invoke with a switch on the type of the actual receiver
-            Kind hubKind = invoke.methodCallTarget().targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver(), hubKind));
-            graph.addBeforeFixed(invoke.node(), receiverHub);
-            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, successors);
-
-            assert invoke.next() == continuation;
-            invoke.setNext(null);
-            returnMerge.setNext(continuation);
-            invoke.node().replaceAtUsages(returnValuePhi);
-            invoke.node().replaceAndDelete(dispatchOnType);
-
-            ArrayList<PiNode> replacements = new ArrayList<>();
-
-            // do the actual inlining for every invoke
-            for (int i = 0; i < numberOfMethods; i++) {
-                BeginNode node = successors[i];
-                Invoke invokeForInlining = (Invoke) node.next();
-
-                ResolvedJavaType commonType = getLeastCommonType(i);
-                ValueNode receiver = invokeForInlining.methodCallTarget().receiver();
-                boolean exact = getTypeCount(i) == 1;
-                PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
-                invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
-                StructuredGraph calleeGraph = calleeGraphs[i];
-                InliningUtil.inline(invokeForInlining, calleeGraph, false);
-                replacements.add(anchoredReceiver);
-            }
-            if (shouldFallbackToInvoke()) {
-                replacements.add(null);
-            }
-            if (GraalOptions.OptTailDuplication) {
-                /*
-                 * We might want to perform tail duplication at the merge after a type switch, if there are invokes that would
-                 * benefit from the improvement in type information.
-                 */
-                FixedNode current = returnMerge;
-                int opportunities = 0;
-                do {
-                    if (current instanceof InvokeNode && ((InvokeNode) current).methodCallTarget().receiver() == originalReceiver) {
-                        opportunities++;
-                    } else if (current.inputs().contains(originalReceiver)) {
-                        opportunities++;
-                    }
-                    current = ((FixedWithNextNode) current).next();
-                } while (current instanceof FixedWithNextNode);
-                if (opportunities > 0) {
-                    metricInliningTailDuplication.increment();
-                    Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements);
-                }
-            }
-        }
-
-        private int getTypeCount(int concreteMethodIndex) {
-            int count = 0;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
-                    count++;
-                }
-            }
-            return count;
-        }
-
-        private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
-            ResolvedJavaType commonType = null;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
-                    if (commonType == null) {
-                        commonType = ptypes[i].getType();
-                    } else {
-                        commonType = commonType.findLeastCommonAncestor(ptypes[i].getType());
-                    }
-                }
-            }
-            assert commonType != null;
-            return commonType;
-        }
-
-        private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
-
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
-            calleeEntryNode.setProbability(invoke.probability());
-            Kind hubKind = invoke.methodCallTarget().targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver(), hubKind));
-            graph.addBeforeFixed(invoke.node(), receiverHub);
-
-            BeginNode unknownTypeSux = BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())));
-            BeginNode[] successors = new BeginNode[] {calleeEntryNode, unknownTypeSux};
-            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, successors);
-
-            FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor();
-            pred.setNext(dispatchOnType);
-            calleeEntryNode.setNext(invoke.node());
-
-            ResolvedJavaMethod concrete = concretes.get(0);
-            StructuredGraph calleeGraph = getGraph(invoke, concrete, runtime, callback);
-            assumptions.recordMethodContents(concrete);
-            InliningUtil.inline(invoke, calleeGraph, false);
-        }
-
-        private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode hub, BeginNode[] successors) {
-            assert ptypes.length > 1;
-
-            ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.length];
-            double[] keyProbabilities = new double[ptypes.length + 1];
-            int[] keySuccessors = new int[ptypes.length + 1];
-            for (int i = 0; i < ptypes.length; i++) {
-                keys[i] = ptypes[i].getType();
-                keyProbabilities[i] = ptypes[i].getProbability();
-                keySuccessors[i] = typesToConcretes[i];
-                assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
-            }
-            keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
-            keySuccessors[keySuccessors.length - 1] = successors.length - 1;
-
-            double[] successorProbabilities = SwitchNode.successorProbabilites(successors.length, keySuccessors, keyProbabilities);
-            TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, successorProbabilities, keys, keyProbabilities, keySuccessors));
-
-            return typeSwitch;
-        }
-
-        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi,
-                        MergeNode exceptionMerge, PhiNode exceptionObjectPhi, double probability, boolean useForInlining) {
-            Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability);
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
-            calleeEntryNode.setNext(duplicatedInvoke.node());
-            calleeEntryNode.setProbability(probability);
-
-            EndNode endNode = graph.add(new EndNode());
-            endNode.setProbability(probability);
-
-            duplicatedInvoke.setNext(endNode);
-            returnMerge.addForwardEnd(endNode);
-
-            if (returnValuePhi != null) {
-                returnValuePhi.addInput(duplicatedInvoke.node());
-            }
-            return calleeEntryNode;
-        }
-
-        private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) {
-            Invoke result = (Invoke) invoke.node().copyWithInputs();
-            Node callTarget = result.callTarget().copyWithInputs();
-            result.node().replaceFirstInput(result.callTarget(), callTarget);
-            result.setUseForInlining(useForInlining);
-            result.setProbability(probability);
-
-            Kind kind = invoke.node().kind();
-            if (!kind.isVoid()) {
-                FrameState stateAfter = invoke.stateAfter();
-                stateAfter = stateAfter.duplicate(stateAfter.bci);
-                stateAfter.replaceFirstInput(invoke.node(), result.node());
-                result.setStateAfter(stateAfter);
-            }
-
-            if (invoke instanceof InvokeWithExceptionNode) {
-                assert exceptionMerge != null && exceptionObjectPhi != null;
-
-                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
-                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
-                FrameState stateAfterException = exceptionObject.stateAfter();
-
-                BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs();
-                ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs();
-                // set new state (pop old exception object, push new one)
-                newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject));
-                newExceptionEdge.setNext(newExceptionObject);
-
-                EndNode endNode = graph.add(new EndNode());
-                newExceptionObject.setNext(endNode);
-                exceptionMerge.addForwardEnd(endNode);
-                exceptionObjectPhi.addInput(newExceptionObject);
-
-                ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
-            }
-            return result;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
-            builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length));
-            for (int i = 0; i < concretes.size(); i++) {
-                builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
-            }
-            return builder.toString();
-        }
-    }
-
-
-    /**
-     * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method,
-     * but for which an assumption has to be registered because of non-final classes.
-     */
-    private static class AssumptionInlineInfo extends ExactInlineInfo {
-        public final ResolvedJavaType context;
-
-        public AssumptionInlineInfo(Invoke invoke, double weight, ResolvedJavaType context, ResolvedJavaMethod concrete) {
-            super(invoke, weight, concrete);
-            this.context = context;
-        }
-
-        @Override
-        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            if (Debug.isLogEnabled()) {
-                String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod());
-                String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete);
-                Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName);
-            }
-            assumptions.recordConcreteMethod(invoke.methodCallTarget().targetMethod(), context, concrete);
-
-            super.inline(graph, runtime, callback, assumptions);
-        }
-
-        @Override
-        public String toString() {
-            return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-    }
-
-    /**
-     * Determines if inlining is possible at the given invoke node.
-     * @param invoke the invoke that should be inlined
-     * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified
-     * @param inliningPolicy used to determine the weight of a specific inlining
-     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
-     */
-    public static InlineInfo getInlineInfo(Invoke invoke, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) {
-        if (!checkInvokeConditions(invoke)) {
-            return null;
-        }
-        ResolvedJavaMethod caller = getCaller(invoke);
-        MethodCallTargetNode callTarget = invoke.methodCallTarget();
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-
-        if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
-            if (!checkTargetConditions(invoke, targetMethod, optimisticOpts, runtime)) {
-                return null;
-            }
-            double weight = inliningPolicy.inliningWeight(caller, targetMethod, invoke);
-            return new ExactInlineInfo(invoke, weight, targetMethod);
-        }
-        ObjectStamp receiverStamp = callTarget.receiver().objectStamp();
-        ResolvedJavaType receiverType = receiverStamp.type();
-        if (receiverStamp.isExactType()) {
-            assert receiverType.isSubtypeOf(targetMethod.getDeclaringClass()) : receiverType + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
-            ResolvedJavaMethod resolved = receiverType.resolveMethod(targetMethod);
-            if (!checkTargetConditions(invoke, resolved, optimisticOpts, runtime)) {
-                return null;
-            }
-            double weight = inliningPolicy.inliningWeight(caller, resolved, invoke);
-            return new ExactInlineInfo(invoke, weight, resolved);
-        }
-        ResolvedJavaType holder = targetMethod.getDeclaringClass();
-
-        if (receiverStamp.type() != null) {
-            // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
-            // TODO (lstadler) fix this
-            if (receiverType != null && receiverType.isSubtypeOf(holder)) {
-                holder = receiverType;
-            }
-        }
-        // TODO (thomaswue) fix this
-        if (assumptions.useOptimisticAssumptions()) {
-            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
-            if (concrete != null) {
-                if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
-                    return null;
-                }
-                double weight = inliningPolicy.inliningWeight(caller, concrete, invoke);
-                return new AssumptionInlineInfo(invoke, weight, holder, concrete);
-            }
-        }
-
-        // type check based inlining
-        return getTypeCheckedInlineInfo(invoke, inliningPolicy, caller, targetMethod, optimisticOpts, runtime);
-    }
-
-    private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, InliningPolicy inliningPolicy, ResolvedJavaMethod caller,
-                    ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) {
-        ProfilingInfo profilingInfo = caller.getProfilingInfo();
-        JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
-        if (typeProfile == null) {
-            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists");
-        }
-
-        ProfiledType[] ptypes = typeProfile.getTypes();
-        if (ptypes == null || ptypes.length <= 0) {
-            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types/probabilities were recorded");
-        }
-
-        double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
-        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
-            if (!optimisticOpts.inlineMonomorphicCalls()) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled");
-            }
-
-            ResolvedJavaType type = ptypes[0].getType();
-            ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
-            if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
-                return null;
-            }
-            double weight = inliningPolicy.inliningWeight(caller, concrete, invoke);
-            return new TypeGuardInlineInfo(invoke, weight, concrete, type);
-        } else {
-            invoke.setMegamorphic(true);
-
-            if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled");
-            }
-            if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled");
-            }
-
-            // TODO (chaeubl) inlining of multiple methods should work differently
-            // 1. check which methods can be inlined
-            // 2. for those methods, use weight and probability to compute which of them should be inlined
-            // 3. do the inlining
-            //    a) all seen methods can be inlined -> do so and guard with deopt
-            //    b) some methods can be inlined -> inline them and fall back to invocation if violated
-
-            // determine concrete methods and map type to specific method
-            ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-            int[] typesToConcretes = new int[ptypes.length];
-            for (int i = 0; i < ptypes.length; i++) {
-                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
-
-                int index = concreteMethods.indexOf(concrete);
-                if (index < 0) {
-                    index = concreteMethods.size();
-                    concreteMethods.add(concrete);
-                }
-                typesToConcretes[i] = index;
-            }
-
-            double totalWeight = 0;
-            for (ResolvedJavaMethod concrete: concreteMethods) {
-                if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
-                    return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
-                }
-                totalWeight += inliningPolicy.inliningWeight(caller, concrete, invoke);
-            }
-            return new MultiTypeGuardInlineInfo(invoke, totalWeight, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
-        }
-    }
-
-
-    private static ResolvedJavaMethod getCaller(Invoke invoke) {
-        return invoke.stateAfter().method();
-    }
-
-    private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
-        // to avoid that floating reads on receiver fields float above the type check
-        return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType)));
-    }
-
-    private static boolean checkInvokeConditions(Invoke invoke) {
-        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
-            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has already been lowered, or has been created as a low-level node");
-        } else if (invoke.methodCallTarget().targetMethod() == null) {
-            return logNotInlinedMethodAndReturnFalse(invoke, "target method is null");
-        } else if (invoke.stateAfter() == null) {
-            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has no after state");
-        } else if (invoke.predecessor() == null || !invoke.node().isAlive()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is dead code");
-        } else if (!invoke.useForInlining()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is marked to be not used for inlining");
-        } else {
-            return true;
-        }
-    }
-
-    private static boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) {
-        if (method == null) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "the method is not resolved");
-        } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(invoke, method, runtime))) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "it is a non-intrinsic native method");
-        } else if (Modifier.isAbstract(method.getModifiers())) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "it is an abstract method");
-        } else if (!method.getDeclaringClass().isInitialized()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "the method's class is not initialized");
-        } else if (!method.canBeInlined()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "it is marked non-inlinable");
-        } else if (computeInliningLevel(invoke) > GraalOptions.MaximumInlineLevel) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum inlining depth");
-        } else if (computeRecursiveInliningLevel(invoke.stateAfter(), method) > GraalOptions.MaximumRecursiveInlining) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum recursive inlining depth");
-        } else if (new OptimisticOptimizations(method).lessOptimisticThan(optimisticOpts)) {
-            return logNotInlinedMethodAndReturnFalse(invoke, method, "the callee uses less optimistic optimizations than caller");
-        } else {
-            return true;
-        }
-    }
-
-    private static int computeInliningLevel(Invoke invoke) {
-        int count = -1;
-        FrameState curState = invoke.stateAfter();
-        while (curState != null) {
-            count++;
-            curState = curState.outerFrameState();
-        }
-        return count;
-    }
-
-    private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) {
-        assert state != null;
-
-        int count = 0;
-        FrameState curState = state;
-        while (curState != null) {
-            if (curState.method() == method) {
-                count++;
-            }
-            curState = curState.outerFrameState();
-        }
-        return count;
-    }
-
-    /**
-     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
-     *
-     * @param invoke the invoke that will be replaced
-     * @param inlineGraph the graph that the invoke will be replaced with
-     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
-     */
-    public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
-        NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
-        StructuredGraph graph = (StructuredGraph) invoke.node().graph();
-
-        FrameState stateAfter = invoke.stateAfter();
-        assert stateAfter.isAlive();
-
-        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
-        ArrayList<Node> nodes = new ArrayList<>();
-        ReturnNode returnNode = null;
-        UnwindNode unwindNode = null;
-        StartNode entryPointNode = inlineGraph.start();
-        FixedNode firstCFGNode = entryPointNode.next();
-        for (Node node : inlineGraph.getNodes()) {
-            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
-                // Do nothing.
-            } else if (node instanceof LocalNode) {
-                replacements.put(node, parameters.get(((LocalNode) node).index()));
-            } else {
-                nodes.add(node);
-                if (node instanceof ReturnNode) {
-                    assert returnNode == null;
-                    returnNode = (ReturnNode) node;
-                } else if (node instanceof UnwindNode) {
-                    assert unwindNode == null;
-                    unwindNode = (UnwindNode) node;
-                }
-            }
-        }
-        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode
-
-        assert invoke.node().successors().first() != null : invoke;
-        assert invoke.node().predecessor() != null;
-
-        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
-        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
-        if (receiverNullCheck) {
-            receiverNullCheck(invoke);
-        }
-        invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate);
-
-        FrameState stateAtExceptionEdge = null;
-        if (invoke instanceof InvokeWithExceptionNode) {
-            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
-            if (unwindNode != null) {
-                assert unwindNode.predecessor() != null;
-                assert invokeWithException.exceptionEdge().successors().count() == 1;
-                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next();
-                stateAtExceptionEdge = obj.stateAfter();
-                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                obj.replaceAtUsages(unwindDuplicate.exception());
-                unwindDuplicate.clearInputs();
-                Node n = obj.next();
-                obj.setNext(null);
-                unwindDuplicate.replaceAndDelete(n);
-            } else {
-                invokeWithException.killExceptionEdge();
-            }
-        } else {
-            if (unwindNode != null) {
-                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId());
-                unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
-                // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state
-                // (because there is no "after exception" frame state!)
-                if (deoptimizeNode.predecessor() instanceof MonitorExitNode) {
-                    MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor();
-                    if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) {
-                        FrameState monitorFrameState = monitorExit.stateAfter();
-                        graph.removeFixed(monitorExit);
-                        monitorFrameState.safeDelete();
-                    }
-                }
-            }
-        }
-
-        FrameState outerFrameState = null;
-        double invokeProbability = invoke.node().probability();
-        for (Node node : duplicates.values()) {
-            if (GraalOptions.ProbabilityAnalysis) {
-                if (node instanceof FixedNode) {
-                    FixedNode fixed = (FixedNode) node;
-                    double newProbability = fixed.probability() * invokeProbability;
-                    if (GraalOptions.LimitInlinedProbability) {
-                        newProbability = Math.min(newProbability, invokeProbability);
-                    }
-                    fixed.setProbability(newProbability);
-                }
-            }
-            if (node instanceof FrameState) {
-                FrameState frameState = (FrameState) node;
-                assert frameState.bci != FrameState.BEFORE_BCI;
-                if (frameState.bci == FrameState.AFTER_BCI) {
-                    frameState.replaceAndDelete(stateAfter);
-                } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) {
-                    if (frameState.isAlive()) {
-                        assert stateAtExceptionEdge != null;
-                        frameState.replaceAndDelete(stateAtExceptionEdge);
-                    } else {
-                        assert stateAtExceptionEdge == null;
-                    }
-                } else {
-                    // only handle the outermost frame states
-                    if (frameState.outerFrameState() == null) {
-                        assert frameState.method() == inlineGraph.method();
-                        if (outerFrameState == null) {
-                            outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
-                            outerFrameState.setDuringCall(true);
-                        }
-                        frameState.setOuterFrameState(outerFrameState);
-                    }
-                }
-            }
-        }
-
-        Node returnValue = null;
-        if (returnNode != null) {
-            if (returnNode.result() instanceof LocalNode) {
-                returnValue = replacements.get(returnNode.result());
-            } else {
-                returnValue = duplicates.get(returnNode.result());
-            }
-            invoke.node().replaceAtUsages(returnValue);
-            Node returnDuplicate = duplicates.get(returnNode);
-            returnDuplicate.clearInputs();
-            Node n = invoke.next();
-            invoke.setNext(null);
-            returnDuplicate.replaceAndDelete(n);
-        }
-
-        invoke.node().clearInputs();
-        invoke.node().replaceAtUsages(null);
-        GraphUtil.killCFG(invoke.node());
-
-        if (stateAfter.usages().isEmpty()) {
-            stateAfter.safeDelete();
-        }
-    }
-
-    public static void receiverNullCheck(Invoke invoke) {
-        MethodCallTargetNode callTarget = invoke.methodCallTarget();
-        StructuredGraph graph = (StructuredGraph) invoke.graph();
-        NodeInputList<ValueNode> parameters = callTarget.arguments();
-        ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
-        if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) {
-            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId())));
-        }
-    }
-
-    public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
-        return getIntrinsicGraph(invoke, target, runtime) != null;
-    }
-
-    private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
-        assert invoke.node().isAlive();
-
-        StructuredGraph intrinsicGraph = (StructuredGraph) target.getCompilerStorage().get(Graph.class);
-        if (intrinsicGraph == null) {
-            // TODO remove once all intrinsics are available via compilerStorage
-            intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments());
-        }
-        return intrinsicGraph;
-    }
-}
+/*
+ * Copyright (c) 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.phases.common;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+public class InliningUtil {
+    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
+    private static final String inliningDecisionsScopeString = "InliningDecisions";
+
+    public interface InliningCallback {
+        StructuredGraph buildGraph(final ResolvedJavaMethod method);
+    }
+
+    public interface InliningPolicy {
+        void initialize(StructuredGraph graph);
+        boolean continueInlining(StructuredGraph graph);
+        InlineInfo next();
+        void scanInvokes(Iterable<? extends Node> newNodes);
+        double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke);
+        boolean isWorthInlining(InlineInfo info);
+    }
+
+    public interface WeightComputationPolicy {
+        double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke);
+    }
+
+    public static void logNotInlinedMethod(InlineInfo info, String msg, Object... args) {
+        logInliningDecision(info, false, msg, args);
+    }
+
+    public static void logInliningDecision(InlineInfo info, boolean success, String msg, final Object... args) {
+        if (shouldLogInliningDecision()) {
+            logInliningDecision(methodName(info), success, msg, args);
+        }
+    }
+
+    public static void logInliningDecision(final String msg, final Object... args) {
+        Debug.scope(inliningDecisionsScopeString, new Runnable() {
+            public void run() {
+                Debug.log(msg, args);
+            }
+        });
+    }
+
+    private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, String msg) {
+        if (shouldLogInliningDecision()) {
+            String methodString = invoke.callTarget() == null ? "callTarget=null" : invoke.callTarget().targetName();
+            logInliningDecision(methodString, false, msg, new Object[0]);
+        }
+        return false;
+    }
+
+    private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, ResolvedJavaMethod method, String msg) {
+        if (shouldLogInliningDecision()) {
+            String methodString = methodName(method, invoke);
+            logInliningDecision(methodString, false, msg, new Object[0]);
+        }
+        return null;
+    }
+
+    private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, ResolvedJavaMethod method, String msg) {
+        if (shouldLogInliningDecision()) {
+            String methodString = methodName(method, invoke);
+            logInliningDecision(methodString, false, msg, new Object[0]);
+        }
+        return false;
+    }
+
+    private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
+        String inliningMsg = "inlining " + methodString + ": " + msg;
+        if (!success) {
+            inliningMsg = "not " + inliningMsg;
+        }
+        logInliningDecision(inliningMsg, args);
+    }
+
+    private static boolean shouldLogInliningDecision() {
+        return Debug.scope(inliningDecisionsScopeString, new Callable<Boolean>() {
+            public Boolean call() {
+                return Debug.isLogEnabled();
+            }
+        });
+    }
+
+    private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
+        if (invoke != null && invoke.stateAfter() != null) {
+            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
+        } else {
+            return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
+        }
+    }
+
+    private static String methodName(InlineInfo info) {
+        if (info == null) {
+            return "null";
+        } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
+            return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
+        } else {
+            return info.toString();
+        }
+    }
+
+    private static String methodName(FrameState frameState, int bci) {
+        StringBuilder sb = new StringBuilder();
+        if (frameState.outerFrameState() != null) {
+            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
+            sb.append("->");
+        }
+        sb.append(MetaUtil.format("%h.%n", frameState.method()));
+        sb.append("@").append(bci);
+        return sb.toString();
+    }
+
+    /**
+     * Represents an opportunity for inlining at the given invoke, with the given weight and level.
+     * The weight is the amortized weight of the additional code - so smaller is better.
+     * The level is the number of nested inlinings that lead to this invoke.
+     */
+    public interface InlineInfo extends Comparable<InlineInfo> {
+        Invoke invoke();
+        double weight();
+        int level();
+        int compiledCodeSize();
+        int compareTo(InlineInfo o);
+
+        /**
+         * Performs the inlining described by this object and returns the node that represents the return value of the
+         * inlined method (or null for void methods and methods that have no non-exceptional exit).
+         */
+        void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions);
+    }
+
+    public abstract static class AbstractInlineInfo implements InlineInfo {
+        protected final Invoke invoke;
+        protected final double weight;
+
+        public AbstractInlineInfo(Invoke invoke, double weight) {
+            this.invoke = invoke;
+            this.weight = weight;
+        }
+
+        @Override
+        public int compareTo(InlineInfo o) {
+            return (weight < o.weight()) ? -1 : (weight > o.weight()) ? 1 : 0;
+        }
+
+        public Invoke invoke() {
+            return invoke;
+        }
+
+        public double weight() {
+            return weight;
+        }
+
+        public int level() {
+            return computeInliningLevel(invoke);
+        }
+
+        protected static StructuredGraph getGraph(final Invoke invoke, final ResolvedJavaMethod concrete, final GraalCodeCacheProvider runtime, final InliningCallback callback) {
+            return Debug.scope("GetInliningGraph", concrete, new Callable<StructuredGraph>() {
+                @Override
+                public StructuredGraph call() throws Exception {
+                    StructuredGraph result = getIntrinsicGraph(invoke, concrete, runtime);
+                    if (result == null) {
+                        assert !Modifier.isNative(concrete.getModifiers());
+                        result = callback.buildGraph(concrete);
+                    }
+                    return result;
+                }
+            });
+        }
+    }
+
+    /**
+     * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and
+     * therefore is able to determine the called method exactly.
+     */
+    private static class ExactInlineInfo extends AbstractInlineInfo {
+        public final ResolvedJavaMethod concrete;
+
+        public ExactInlineInfo(Invoke invoke, double weight, ResolvedJavaMethod concrete) {
+            super(invoke, weight);
+            this.concrete = concrete;
+        }
+
+        @Override
+        public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
+            StructuredGraph graph = getGraph(invoke, concrete, runtime, callback);
+            assumptions.recordMethodContents(concrete);
+            InliningUtil.inline(invoke, graph, true);
+        }
+
+        @Override
+        public int compiledCodeSize() {
+            return concrete.getCompiledCodeSize();
+        }
+
+        @Override
+        public String toString() {
+            return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
+        }
+    }
+
+    /**
+     * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which
+     * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed.
+     */
+    private static class TypeGuardInlineInfo extends AbstractInlineInfo {
+        public final ResolvedJavaMethod concrete;
+        public final ResolvedJavaType type;
+
+        public TypeGuardInlineInfo(Invoke invoke, double weight, ResolvedJavaMethod concrete, ResolvedJavaType type) {
+            super(invoke, weight);
+            this.concrete = concrete;
+            this.type = type;
+        }
+
+        @Override
+        public int compiledCodeSize() {
+            return concrete.getCompiledCodeSize();
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
+            // receiver null check must be before the type check
+            InliningUtil.receiverNullCheck(invoke);
+            ValueNode receiver = invoke.methodCallTarget().receiver();
+            ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), runtime, graph);
+            LoadHubNode receiverHub = graph.add(new LoadHubNode(receiver, typeHub.kind()));
+            CompareNode typeCheck = CompareNode.createCompareNode(Condition.EQ, receiverHub, typeHub);
+            FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId()));
+            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
+            assert invoke.predecessor() != null;
+
+            ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true);
+            invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+            graph.addBeforeFixed(invoke.node(), receiverHub);
+            graph.addBeforeFixed(invoke.node(), guard);
+            graph.addBeforeFixed(invoke.node(), anchor);
+
+            StructuredGraph calleeGraph = getGraph(invoke, concrete, runtime, callback);
+            assumptions.recordMethodContents(concrete);
+            InliningUtil.inline(invoke, calleeGraph, false);
+        }
+
+        @Override
+        public String toString() {
+            return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete);
+        }
+    }
+
+    /**
+     * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable
+     * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered.
+     */
+    private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
+        public final List<ResolvedJavaMethod> concretes;
+        public final ProfiledType[] ptypes;
+        public final int[] typesToConcretes;
+        public final double notRecordedTypeProbability;
+
+        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, List<ResolvedJavaMethod> concretes, ProfiledType[] ptypes,
+                        int[] typesToConcretes, double notRecordedTypeProbability) {
+            super(invoke, weight);
+            assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods";
+            assert ptypes.length == typesToConcretes.length : "array lengths must match";
+
+            this.concretes = concretes;
+            this.ptypes = ptypes;
+            this.typesToConcretes = typesToConcretes;
+            this.notRecordedTypeProbability = notRecordedTypeProbability;
+        }
+
+        @Override
+        public int compiledCodeSize() {
+            int result = 0;
+            for (ResolvedJavaMethod m: concretes) {
+                result += m.getCompiledCodeSize();
+            }
+            return result;
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
+            int numberOfMethods = concretes.size();
+            boolean hasReturnValue = invoke.node().kind() != Kind.Void;
+
+            // receiver null check must be the first node
+            InliningUtil.receiverNullCheck(invoke);
+            if (numberOfMethods > 1 || shouldFallbackToInvoke()) {
+                inlineMultipleMethods(graph, runtime, callback, assumptions, numberOfMethods, hasReturnValue);
+            } else {
+                inlineSingleMethod(graph, runtime, callback, assumptions);
+            }
+        }
+
+        private boolean shouldFallbackToInvoke() {
+            return notRecordedTypeProbability > 0;
+        }
+
+        private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions, int numberOfMethods, boolean hasReturnValue) {
+            FixedNode continuation = invoke.next();
+
+            ValueNode originalReceiver = invoke.methodCallTarget().receiver();
+            // setup merge and phi nodes for results and exceptions
+            MergeNode returnMerge = graph.add(new MergeNode());
+            returnMerge.setProbability(invoke.probability());
+            returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci));
+
+            PhiNode returnValuePhi = null;
+            if (hasReturnValue) {
+                returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge));
+            }
+
+            MergeNode exceptionMerge = null;
+            PhiNode exceptionObjectPhi = null;
+            if (invoke instanceof InvokeWithExceptionNode) {
+                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+                DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+
+                exceptionMerge = graph.add(new MergeNode());
+                exceptionMerge.setProbability(exceptionEdge.probability());
+
+                FixedNode exceptionSux = exceptionObject.next();
+                graph.addBeforeFixed(exceptionSux, exceptionMerge);
+                exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge));
+                exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi));
+            }
+
+            // create one separate block for each invoked method
+            BeginNode[] successors = new BeginNode[numberOfMethods + 1];
+            for (int i = 0; i < numberOfMethods; i++) {
+                double probability = 0;
+                for (int j = 0; j < typesToConcretes.length; j++) {
+                    if (typesToConcretes[j] == i) {
+                        probability += ptypes[j].getProbability();
+                    }
+                }
+
+                successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, invoke.probability() * probability, true);
+            }
+
+            // create the successor for an unknown type
+            FixedNode unknownTypeSux;
+            if (shouldFallbackToInvoke()) {
+                unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, notRecordedTypeProbability, false);
+            } else {
+                unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId()));
+            }
+            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+
+            // replace the invoke exception edge
+            if (invoke instanceof InvokeWithExceptionNode) {
+                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
+                BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+                exceptionObject.replaceAtUsages(exceptionObjectPhi);
+                exceptionObject.setNext(null);
+                GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
+            }
+
+            // get all graphs and record assumptions
+            assert invoke.node().isAlive();
+            StructuredGraph[] calleeGraphs = new StructuredGraph[numberOfMethods];
+            for (int i = 0; i < numberOfMethods; i++) {
+                ResolvedJavaMethod concrete = concretes.get(i);
+                calleeGraphs[i] = getGraph(invoke, concrete, runtime, callback);
+                assumptions.recordMethodContents(concrete);
+            }
+
+            // replace the invoke with a switch on the type of the actual receiver
+            Kind hubKind = invoke.methodCallTarget().targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
+            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver(), hubKind));
+            graph.addBeforeFixed(invoke.node(), receiverHub);
+            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, successors);
+
+            assert invoke.next() == continuation;
+            invoke.setNext(null);
+            returnMerge.setNext(continuation);
+            invoke.node().replaceAtUsages(returnValuePhi);
+            invoke.node().replaceAndDelete(dispatchOnType);
+
+            ArrayList<PiNode> replacements = new ArrayList<>();
+
+            // do the actual inlining for every invoke
+            for (int i = 0; i < numberOfMethods; i++) {
+                BeginNode node = successors[i];
+                Invoke invokeForInlining = (Invoke) node.next();
+
+                ResolvedJavaType commonType = getLeastCommonType(i);
+                ValueNode receiver = invokeForInlining.methodCallTarget().receiver();
+                boolean exact = getTypeCount(i) == 1;
+                PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
+                invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+                StructuredGraph calleeGraph = calleeGraphs[i];
+                InliningUtil.inline(invokeForInlining, calleeGraph, false);
+                replacements.add(anchoredReceiver);
+            }
+            if (shouldFallbackToInvoke()) {
+                replacements.add(null);
+            }
+            if (GraalOptions.OptTailDuplication) {
+                /*
+                 * We might want to perform tail duplication at the merge after a type switch, if there are invokes that would
+                 * benefit from the improvement in type information.
+                 */
+                FixedNode current = returnMerge;
+                int opportunities = 0;
+                do {
+                    if (current instanceof InvokeNode && ((InvokeNode) current).methodCallTarget().receiver() == originalReceiver) {
+                        opportunities++;
+                    } else if (current.inputs().contains(originalReceiver)) {
+                        opportunities++;
+                    }
+                    current = ((FixedWithNextNode) current).next();
+                } while (current instanceof FixedWithNextNode);
+                if (opportunities > 0) {
+                    metricInliningTailDuplication.increment();
+                    Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
+                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements);
+                }
+            }
+        }
+
+        private int getTypeCount(int concreteMethodIndex) {
+            int count = 0;
+            for (int i = 0; i < typesToConcretes.length; i++) {
+                if (typesToConcretes[i] == concreteMethodIndex) {
+                    count++;
+                }
+            }
+            return count;
+        }
+
+        private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
+            ResolvedJavaType commonType = null;
+            for (int i = 0; i < typesToConcretes.length; i++) {
+                if (typesToConcretes[i] == concreteMethodIndex) {
+                    if (commonType == null) {
+                        commonType = ptypes[i].getType();
+                    } else {
+                        commonType = commonType.findLeastCommonAncestor(ptypes[i].getType());
+                    }
+                }
+            }
+            assert commonType != null;
+            return commonType;
+        }
+
+        private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
+            assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+            BeginNode calleeEntryNode = graph.add(new BeginNode());
+            calleeEntryNode.setProbability(invoke.probability());
+            Kind hubKind = invoke.methodCallTarget().targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
+            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver(), hubKind));
+            graph.addBeforeFixed(invoke.node(), receiverHub);
+
+            BeginNode unknownTypeSux = BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())));
+            BeginNode[] successors = new BeginNode[] {calleeEntryNode, unknownTypeSux};
+            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, successors);
+
+            FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor();
+            pred.setNext(dispatchOnType);
+            calleeEntryNode.setNext(invoke.node());
+
+            ResolvedJavaMethod concrete = concretes.get(0);
+            StructuredGraph calleeGraph = getGraph(invoke, concrete, runtime, callback);
+            assumptions.recordMethodContents(concrete);
+            InliningUtil.inline(invoke, calleeGraph, false);
+        }
+
+        private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode hub, BeginNode[] successors) {
+            assert ptypes.length > 1;
+
+            ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.length];
+            double[] keyProbabilities = new double[ptypes.length + 1];
+            int[] keySuccessors = new int[ptypes.length + 1];
+            for (int i = 0; i < ptypes.length; i++) {
+                keys[i] = ptypes[i].getType();
+                keyProbabilities[i] = ptypes[i].getProbability();
+                keySuccessors[i] = typesToConcretes[i];
+                assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
+            }
+            keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
+            keySuccessors[keySuccessors.length - 1] = successors.length - 1;
+
+            double[] successorProbabilities = SwitchNode.successorProbabilites(successors.length, keySuccessors, keyProbabilities);
+            TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, successorProbabilities, keys, keyProbabilities, keySuccessors));
+
+            return typeSwitch;
+        }
+
+        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi,
+                        MergeNode exceptionMerge, PhiNode exceptionObjectPhi, double probability, boolean useForInlining) {
+            Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability);
+            BeginNode calleeEntryNode = graph.add(new BeginNode());
+            calleeEntryNode.setNext(duplicatedInvoke.node());
+            calleeEntryNode.setProbability(probability);
+
+            EndNode endNode = graph.add(new EndNode());
+            endNode.setProbability(probability);
+
+            duplicatedInvoke.setNext(endNode);
+            returnMerge.addForwardEnd(endNode);
+
+            if (returnValuePhi != null) {
+                returnValuePhi.addInput(duplicatedInvoke.node());
+            }
+            return calleeEntryNode;
+        }
+
+        private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) {
+            Invoke result = (Invoke) invoke.node().copyWithInputs();
+            Node callTarget = result.callTarget().copyWithInputs();
+            result.node().replaceFirstInput(result.callTarget(), callTarget);
+            result.setUseForInlining(useForInlining);
+            result.setProbability(probability);
+
+            Kind kind = invoke.node().kind();
+            if (!kind.isVoid()) {
+                FrameState stateAfter = invoke.stateAfter();
+                stateAfter = stateAfter.duplicate(stateAfter.bci);
+                stateAfter.replaceFirstInput(invoke.node(), result.node());
+                result.setStateAfter(stateAfter);
+            }
+
+            if (invoke instanceof InvokeWithExceptionNode) {
+                assert exceptionMerge != null && exceptionObjectPhi != null;
+
+                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+                FrameState stateAfterException = exceptionObject.stateAfter();
+
+                BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs();
+                ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs();
+                // set new state (pop old exception object, push new one)
+                newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject));
+                newExceptionEdge.setNext(newExceptionObject);
+
+                EndNode endNode = graph.add(new EndNode());
+                newExceptionObject.setNext(endNode);
+                exceptionMerge.addForwardEnd(endNode);
+                exceptionObjectPhi.addInput(newExceptionObject);
+
+                ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+            }
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
+            builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length));
+            for (int i = 0; i < concretes.size(); i++) {
+                builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
+            }
+            return builder.toString();
+        }
+    }
+
+
+    /**
+     * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method,
+     * but for which an assumption has to be registered because of non-final classes.
+     */
+    private static class AssumptionInlineInfo extends ExactInlineInfo {
+        public final ResolvedJavaType context;
+
+        public AssumptionInlineInfo(Invoke invoke, double weight, ResolvedJavaType context, ResolvedJavaMethod concrete) {
+            super(invoke, weight, concrete);
+            this.context = context;
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
+            if (Debug.isLogEnabled()) {
+                String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod());
+                String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete);
+                Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName);
+            }
+            assumptions.recordConcreteMethod(invoke.methodCallTarget().targetMethod(), context, concrete);
+
+            super.inline(graph, runtime, callback, assumptions);
+        }
+
+        @Override
+        public String toString() {
+            return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
+        }
+    }
+
+    /**
+     * Determines if inlining is possible at the given invoke node.
+     * @param invoke the invoke that should be inlined
+     * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified
+     * @param inliningPolicy used to determine the weight of a specific inlining
+     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
+     */
+    public static InlineInfo getInlineInfo(Invoke invoke, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) {
+        if (!checkInvokeConditions(invoke)) {
+            return null;
+        }
+        ResolvedJavaMethod caller = getCaller(invoke);
+        MethodCallTargetNode callTarget = invoke.methodCallTarget();
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+
+        if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+            if (!checkTargetConditions(invoke, targetMethod, optimisticOpts, runtime)) {
+                return null;
+            }
+            double weight = inliningPolicy.inliningWeight(caller, targetMethod, invoke);
+            return new ExactInlineInfo(invoke, weight, targetMethod);
+        }
+        ObjectStamp receiverStamp = callTarget.receiver().objectStamp();
+        ResolvedJavaType receiverType = receiverStamp.type();
+        if (receiverStamp.isExactType()) {
+            assert receiverType.isSubtypeOf(targetMethod.getDeclaringClass()) : receiverType + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+            ResolvedJavaMethod resolved = receiverType.resolveMethod(targetMethod);
+            if (!checkTargetConditions(invoke, resolved, optimisticOpts, runtime)) {
+                return null;
+            }
+            double weight = inliningPolicy.inliningWeight(caller, resolved, invoke);
+            return new ExactInlineInfo(invoke, weight, resolved);
+        }
+        ResolvedJavaType holder = targetMethod.getDeclaringClass();
+
+        if (receiverStamp.type() != null) {
+            // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
+            // TODO (lstadler) fix this
+            if (receiverType != null && receiverType.isSubtypeOf(holder)) {
+                holder = receiverType;
+            }
+        }
+        // TODO (thomaswue) fix this
+        if (assumptions.useOptimisticAssumptions()) {
+            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
+            if (concrete != null) {
+                if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
+                    return null;
+                }
+                double weight = inliningPolicy.inliningWeight(caller, concrete, invoke);
+                return new AssumptionInlineInfo(invoke, weight, holder, concrete);
+            }
+        }
+
+        // type check based inlining
+        return getTypeCheckedInlineInfo(invoke, inliningPolicy, caller, targetMethod, optimisticOpts, runtime);
+    }
+
+    private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, InliningPolicy inliningPolicy, ResolvedJavaMethod caller,
+                    ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) {
+        ProfilingInfo profilingInfo = caller.getProfilingInfo();
+        JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
+        if (typeProfile == null) {
+            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists");
+        }
+
+        ProfiledType[] ptypes = typeProfile.getTypes();
+        if (ptypes == null || ptypes.length <= 0) {
+            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types/probabilities were recorded");
+        }
+
+        double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+            if (!optimisticOpts.inlineMonomorphicCalls()) {
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled");
+            }
+
+            ResolvedJavaType type = ptypes[0].getType();
+            ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
+            if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
+                return null;
+            }
+            double weight = inliningPolicy.inliningWeight(caller, concrete, invoke);
+            return new TypeGuardInlineInfo(invoke, weight, concrete, type);
+        } else {
+            invoke.setPolymorphic(true);
+
+
+            if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled");
+            }
+            if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled");
+            }
+
+            // TODO (chaeubl) inlining of multiple methods should work differently
+            // 1. check which methods can be inlined
+            // 2. for those methods, use weight and probability to compute which of them should be inlined
+            // 3. do the inlining
+            //    a) all seen methods can be inlined -> do so and guard with deopt
+            //    b) some methods can be inlined -> inline them and fall back to invocation if violated
+
+            // determine concrete methods and map type to specific method
+            ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
+            int[] typesToConcretes = new int[ptypes.length];
+            for (int i = 0; i < ptypes.length; i++) {
+                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
+
+                int index = concreteMethods.indexOf(concrete);
+                if (index < 0) {
+                    index = concreteMethods.size();
+                    concreteMethods.add(concrete);
+                }
+                typesToConcretes[i] = index;
+            }
+
+            double totalWeight = 0;
+            for (ResolvedJavaMethod concrete: concreteMethods) {
+                if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
+                    return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
+                }
+                totalWeight += inliningPolicy.inliningWeight(caller, concrete, invoke);
+            }
+            return new MultiTypeGuardInlineInfo(invoke, totalWeight, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
+        }
+    }
+
+
+    private static ResolvedJavaMethod getCaller(Invoke invoke) {
+        return invoke.stateAfter().method();
+    }
+
+    private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
+        // to avoid that floating reads on receiver fields float above the type check
+        return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType)));
+    }
+
+    private static boolean checkInvokeConditions(Invoke invoke) {
+        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has already been lowered, or has been created as a low-level node");
+        } else if (invoke.methodCallTarget().targetMethod() == null) {
+            return logNotInlinedMethodAndReturnFalse(invoke, "target method is null");
+        } else if (invoke.stateAfter() == null) {
+            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has no after state");
+        } else if (invoke.predecessor() == null || !invoke.node().isAlive()) {
+            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is dead code");
+        } else if (!invoke.useForInlining()) {
+            return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is marked to be not used for inlining");
+        } else {
+            return true;
+        }
+    }
+
+    private static boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) {
+        if (method == null) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "the method is not resolved");
+        } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(invoke, method, runtime))) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "it is a non-intrinsic native method");
+        } else if (Modifier.isAbstract(method.getModifiers())) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "it is an abstract method");
+        } else if (!method.getDeclaringClass().isInitialized()) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "the method's class is not initialized");
+        } else if (!method.canBeInlined()) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "it is marked non-inlinable");
+        } else if (computeInliningLevel(invoke) > GraalOptions.MaximumInlineLevel) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum inlining depth");
+        } else if (computeRecursiveInliningLevel(invoke.stateAfter(), method) > GraalOptions.MaximumRecursiveInlining) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum recursive inlining depth");
+        } else if (new OptimisticOptimizations(method).lessOptimisticThan(optimisticOpts)) {
+            return logNotInlinedMethodAndReturnFalse(invoke, method, "the callee uses less optimistic optimizations than caller");
+        } else {
+            return true;
+        }
+    }
+
+    private static int computeInliningLevel(Invoke invoke) {
+        int count = -1;
+        FrameState curState = invoke.stateAfter();
+        while (curState != null) {
+            count++;
+            curState = curState.outerFrameState();
+        }
+        return count;
+    }
+
+    private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) {
+        assert state != null;
+
+        int count = 0;
+        FrameState curState = state;
+        while (curState != null) {
+            if (curState.method() == method) {
+                count++;
+            }
+            curState = curState.outerFrameState();
+        }
+        return count;
+    }
+
+    /**
+     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+     *
+     * @param invoke the invoke that will be replaced
+     * @param inlineGraph the graph that the invoke will be replaced with
+     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
+     */
+    public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+        NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
+        StructuredGraph graph = (StructuredGraph) invoke.node().graph();
+
+        FrameState stateAfter = invoke.stateAfter();
+        assert stateAfter.isAlive();
+
+        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+        ArrayList<Node> nodes = new ArrayList<>();
+        ReturnNode returnNode = null;
+        UnwindNode unwindNode = null;
+        StartNode entryPointNode = inlineGraph.start();
+        FixedNode firstCFGNode = entryPointNode.next();
+        for (Node node : inlineGraph.getNodes()) {
+            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
+                // Do nothing.
+            } else if (node instanceof LocalNode) {
+                replacements.put(node, parameters.get(((LocalNode) node).index()));
+            } else {
+                nodes.add(node);
+                if (node instanceof ReturnNode) {
+                    assert returnNode == null;
+                    returnNode = (ReturnNode) node;
+                } else if (node instanceof UnwindNode) {
+                    assert unwindNode == null;
+                    unwindNode = (UnwindNode) node;
+                }
+            }
+        }
+        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode
+
+        assert invoke.node().successors().first() != null : invoke;
+        assert invoke.node().predecessor() != null;
+
+        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
+        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+        if (receiverNullCheck) {
+            receiverNullCheck(invoke);
+        }
+        invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate);
+
+        FrameState stateAtExceptionEdge = null;
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+            if (unwindNode != null) {
+                assert unwindNode.predecessor() != null;
+                assert invokeWithException.exceptionEdge().successors().count() == 1;
+                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next();
+                stateAtExceptionEdge = obj.stateAfter();
+                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                obj.replaceAtUsages(unwindDuplicate.exception());
+                unwindDuplicate.clearInputs();
+                Node n = obj.next();
+                obj.setNext(null);
+                unwindDuplicate.replaceAndDelete(n);
+            } else {
+                invokeWithException.killExceptionEdge();
+            }
+        } else {
+            if (unwindNode != null) {
+                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId());
+                unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
+                // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state
+                // (because there is no "after exception" frame state!)
+                if (deoptimizeNode.predecessor() instanceof MonitorExitNode) {
+                    MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor();
+                    if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) {
+                        FrameState monitorFrameState = monitorExit.stateAfter();
+                        graph.removeFixed(monitorExit);
+                        monitorFrameState.safeDelete();
+                    }
+                }
+            }
+        }
+
+        FrameState outerFrameState = null;
+        double invokeProbability = invoke.node().probability();
+        for (Node node : duplicates.values()) {
+            if (GraalOptions.ProbabilityAnalysis) {
+                if (node instanceof FixedNode) {
+                    FixedNode fixed = (FixedNode) node;
+                    double newProbability = fixed.probability() * invokeProbability;
+                    if (GraalOptions.LimitInlinedProbability) {
+                        newProbability = Math.min(newProbability, invokeProbability);
+                    }
+                    fixed.setProbability(newProbability);
+                }
+            }
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+                assert frameState.bci != FrameState.BEFORE_BCI;
+                if (frameState.bci == FrameState.AFTER_BCI) {
+                    frameState.replaceAndDelete(stateAfter);
+                } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) {
+                    if (frameState.isAlive()) {
+                        assert stateAtExceptionEdge != null;
+                        frameState.replaceAndDelete(stateAtExceptionEdge);
+                    } else {
+                        assert stateAtExceptionEdge == null;
+                    }
+                } else {
+                    // only handle the outermost frame states
+                    if (frameState.outerFrameState() == null) {
+                        assert frameState.method() == inlineGraph.method();
+                        if (outerFrameState == null) {
+                            outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
+                            outerFrameState.setDuringCall(true);
+                        }
+                        frameState.setOuterFrameState(outerFrameState);
+                    }
+                }
+            }
+        }
+
+        Node returnValue = null;
+        if (returnNode != null) {
+            if (returnNode.result() instanceof LocalNode) {
+                returnValue = replacements.get(returnNode.result());
+            } else {
+                returnValue = duplicates.get(returnNode.result());
+            }
+            invoke.node().replaceAtUsages(returnValue);
+            Node returnDuplicate = duplicates.get(returnNode);
+            returnDuplicate.clearInputs();
+            Node n = invoke.next();
+            invoke.setNext(null);
+            returnDuplicate.replaceAndDelete(n);
+        }
+
+        invoke.node().replaceAtUsages(null);
+        GraphUtil.killCFG(invoke.node());
+    }
+
+    public static void receiverNullCheck(Invoke invoke) {
+        MethodCallTargetNode callTarget = invoke.methodCallTarget();
+        StructuredGraph graph = (StructuredGraph) invoke.graph();
+        NodeInputList<ValueNode> parameters = callTarget.arguments();
+        ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
+        if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) {
+            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId())));
+        }
+    }
+
+    public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
+        return getIntrinsicGraph(invoke, target, runtime) != null;
+    }
+
+    private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
+        assert invoke.node().isAlive();
+
+        StructuredGraph intrinsicGraph = (StructuredGraph) target.getCompilerStorage().get(Graph.class);
+        if (intrinsicGraph == null) {
+            // TODO remove once all intrinsics are available via compilerStorage
+            intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments());
+        }
+        return intrinsicGraph;
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Nov 26 10:57:02 2012 +0100
@@ -142,7 +142,6 @@
     public static int     PrintBinaryGraphPort               = 4445;
 
     // Other printing settings
-    public static boolean PrintAddressMap                    = ____;
     public static boolean PrintQueue                         = ____;
     public static boolean PrintCompilation                   = ____;
     public static boolean PrintProfilingInformation          = ____;
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Mon Nov 26 10:57:02 2012 +0100
@@ -389,8 +389,8 @@
 
     private static boolean checkConstantArgument(final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) {
         if (kind.isObject()) {
-            Class<?> type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()).toJava();
-            assert arg == null || type.isInstance(arg) :
+            ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass());
+            assert arg == null || type.isInstance(Constant.forObject(arg)) :
                 method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName();
         } else {
             assert arg != null && kind.toBoxedJavaClass() == arg.getClass() :
@@ -402,9 +402,8 @@
     private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) {
         Object arg = varargs.getArray();
         ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
-        Class< ? > javaType = type.toJava();
-        assert javaType.isArray() : "varargs parameter must be an array type";
-        assert javaType.isInstance(arg) : "value for " + name + " is not a " + javaType.getName() + " instance: " + arg;
+        assert type.isArrayClass() : "varargs parameter must be an array type";
+        assert type.isInstance(Constant.forObject(arg)) : "value for " + name + " is not a " + MetaUtil.toJavaName(type) + " instance: " + arg;
         return true;
     }
 
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetVerificationPhase.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetVerificationPhase.java	Mon Nov 26 10:57:02 2012 +0100
@@ -83,7 +83,7 @@
                             ValueNode argument = arguments.get(argc);
                             if (argument == node) {
                                 ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
-                                verify((type.toJava() == Word.class) == isWord(argument), node, invoke.node(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
+                                verify((type.isClass(Word.class)) == isWord(argument), node, invoke.node(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
                             }
                             argc++;
                         }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java	Mon Nov 26 10:57:02 2012 +0100
@@ -101,27 +101,11 @@
     }
 
     @Override
-    public EscapeOp getEscapeOp() {
-        if (!shouldRevirtualize(this)) {
-            return null;
+    public ObjectDesc[] getAllocations(long nextVirtualId, MetaAccessProvider metaAccess) {
+        if (shouldRevirtualize(this)) {
+            return new ObjectDesc[] {new ObjectDesc(virtualObject, values.toArray(new ValueNode[values.size()]), lockCount)};
         }
-        return new EscapeOp() {
-
-            @Override
-            public ValueNode[] fieldState() {
-                return values.toArray(new ValueNode[values.size()]);
-            }
-
-            @Override
-            public VirtualObjectNode virtualObject(long virtualId) {
-                return virtualObject;
-            }
-
-            @Override
-            public int lockCount() {
-                return lockCount;
-            }
-        };
+        return null;
     }
 
     private boolean shouldRevirtualize(MaterializeObjectNode materializeObjectNode) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Mon Nov 26 10:57:02 2012 +0100
@@ -158,8 +158,10 @@
 
     void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) {
         objectAliases.put(node, virtual);
-        for (Node usage : node.usages()) {
-            markVirtualUsages(usage, usages);
+        if (node.isAlive()) {
+            for (Node usage : node.usages()) {
+                markVirtualUsages(usage, usages);
+            }
         }
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon Nov 26 10:57:02 2012 +0100
@@ -40,11 +40,13 @@
     private final TargetDescription target;
     private final MetaAccessProvider runtime;
     private final Assumptions assumptions;
+    private final boolean iterative;
 
-    public PartialEscapeAnalysisPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
+    public PartialEscapeAnalysisPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, boolean iterative) {
         this.target = target;
         this.runtime = runtime;
         this.assumptions = assumptions;
+        this.iterative = iterative;
     }
 
     public static final void trace(String format, Object... obj) {
@@ -87,6 +89,9 @@
                     assert noObsoleteNodes(graph, obsoleteNodes);
 
                     new DeadCodeEliminationPhase().apply(graph);
+                    if (!iterative) {
+                        return;
+                    }
                     if (GraalOptions.OptCanonicalizer) {
                         new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
                     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Nov 26 10:51:39 2012 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Nov 26 10:57:02 2012 +0100
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.spi.EscapeAnalyzable.ObjectDesc;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
@@ -71,10 +72,12 @@
     private int virtualIds = 0;
 
     private final VirtualizerToolImpl tool;
+    private final MetaAccessProvider metaAccess;
 
     public PartialEscapeClosure(NodeBitMap usages, SchedulePhase schedule, MetaAccessProvider metaAccess) {
         this.usages = usages;
         this.schedule = schedule;
+        this.metaAccess = metaAccess;
         tool = new VirtualizerToolImpl(effects, usages, metaAccess);
     }
 
@@ -93,29 +96,32 @@
 
         FixedWithNextNode lastFixedNode = null;
         for (Node node : nodeList) {
-            EscapeOp op = null;
+            ObjectDesc[] newAllocations = null;
             if (node instanceof EscapeAnalyzable) {
-                op = ((EscapeAnalyzable) node).getEscapeOp();
+                newAllocations = ((EscapeAnalyzable) node).getAllocations(virtualIds, metaAccess);
             }
 
-            if (op != null) {
+            if (newAllocations != null) {
                 trace("{{%s}} ", node);
-                VirtualObjectNode virtualObject = op.virtualObject(virtualIds);
-                if (virtualObject.isAlive()) {
-                    reusedVirtualObjects.add(virtualObject);
+                for (ObjectDesc desc : newAllocations) {
+                    VirtualObjectNode virtualObject = desc.virtualObject;
+                    if (virtualObject.isAlive()) {
+                        reusedVirtualObjects.add(virtualObject);
+                        state.addAndMarkAlias(virtualObject, virtualObject, usages);
+                    } else {
+                        effects.addFloatingNode(virtualObject);
+                    }
+                    ValueNode[] fieldState = desc.entryState;
+                    for (int i = 0; i < fieldState.length; i++) {
+                        fieldState[i] = state.getScalarAlias(fieldState[i]);
+                    }
+                    state.addObject(virtualObject, new ObjectState(virtualObject, fieldState, desc.lockCount));
                     state.addAndMarkAlias(virtualObject, virtualObject, usages);
-                } else {
-                    effects.addFloatingNode(virtualObject);
                 }
-                ValueNode[] fieldState = op.fieldState();
-                for (int i = 0; i < fieldState.length; i++) {
-                    fieldState[i] = state.getScalarAlias(fieldState[i]);
-                }
-                state.addObject(virtualObject, new ObjectState(virtualObject, fieldState, op.lockCount()));
-                state.addAndMarkAlias(virtualObject, (ValueNode) node, usages);
+                state.addAndMarkAlias(newAllocations[0].virtualObject, (ValueNode) node, usages);
                 effects.deleteFixedNode((FixedWithNextNode) node);
-                virtualIds++;
-                metricAllocationRemoved.increment();
+                metricAllocationRemoved.add(newAllocations.length);
+                virtualIds += newAllocations.length;
             } else {
                 if (usages.isMarked(node)) {
                     trace("[[%s]] ", node);
--- a/mx/projects	Mon Nov 26 10:51:39 2012 +0100
+++ b/mx/projects	Mon Nov 26 10:57:02 2012 +0100
@@ -41,6 +41,13 @@
 project@com.oracle.graal.api.meta@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.api.meta@javaCompliance=1.7
 
+# graal.api.meta.test
+project@com.oracle.graal.api.meta.test@subDir=graal
+project@com.oracle.graal.api.meta.test@sourceDirs=src
+project@com.oracle.graal.api.meta.test@dependencies=JUNIT,com.oracle.graal.api.meta,com.oracle.graal.api.runtime
+project@com.oracle.graal.api.meta.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.api.meta.test@javaCompliance=1.7
+
 # graal.api.code
 project@com.oracle.graal.api.code@subDir=graal
 project@com.oracle.graal.api.code@sourceDirs=src
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon Nov 26 10:51:39 2012 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon Nov 26 10:57:02 2012 +0100
@@ -625,14 +625,13 @@
     TRACE_graal_3("relocating (stub)  at %p", inst);
   } else { // method != NULL
     assert(hotspot_method != NULL, "unexpected JavaMethod");
-    assert(debug_info != NULL, "debug info expected");
-
+#ifdef ASSERT
     Method* method = NULL;
     // we need to check, this might also be an unresolved method
     if (hotspot_method->is_a(HotSpotResolvedJavaMethod::klass())) {
       method = getMethodFromHotSpotMethod(hotspot_method);
     }
-
+#endif
     assert(debug_info != NULL, "debug info expected");
 
     TRACE_graal_3("method call");