changeset 8617:6d884611d4c1

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Wed, 03 Apr 2013 14:41:22 +0200
parents d343737786fe (current diff) c7672a325faf (diff)
children 832b9a115a2d
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MonitorValue.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPost.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPre.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrierPost.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.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.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java src/cpu/x86/vm/templateInterpreter_x86.hpp
diffstat 128 files changed, 3741 insertions(+), 1919 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Mar 28 17:11:06 2013 +0100
+++ b/.hgignore	Wed Apr 03 14:41:22 2013 +0200
@@ -67,5 +67,6 @@
 *.bgv
 core.*
 *.jar
+*.jar.*
 eclipse-build.xml
 rebuild-launch.out
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Wed Apr 03 14:41:22 2013 +0200
@@ -43,11 +43,6 @@
     InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult);
 
     /**
-     * Returns the size in bytes for locking information on the stack.
-     */
-    int getSizeOfLockData();
-
-    /**
      * Returns a disassembly of some compiled code.
      * 
      * @param compResult some compiled code
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MonitorValue.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2011, 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.api.code;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * Represents lock information in the debug information.
- */
-public final class MonitorValue extends Value {
-
-    private static final long serialVersionUID = 8241681800464483691L;
-
-    private Value owner;
-    private final Value lockData;
-    private final boolean eliminated;
-
-    public MonitorValue(Value owner, Value lockData, boolean eliminated) {
-        super(Kind.Illegal);
-        this.owner = owner;
-        this.lockData = lockData;
-        this.eliminated = eliminated;
-    }
-
-    public Value getOwner() {
-        return owner;
-    }
-
-    public void setOwner(Value newOwner) {
-        this.owner = newOwner;
-    }
-
-    public Value getLockData() {
-        return lockData;
-    }
-
-    public boolean isEliminated() {
-        return eliminated;
-    }
-
-    @Override
-    public String toString() {
-        return "monitor[" + owner + (lockData != null ? ", " + lockData : "") + (eliminated ? ", eliminated" : "") + "]";
-    }
-}
--- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java	Wed Apr 03 14:41:22 2013 +0200
@@ -36,26 +36,38 @@
         try {
             runtime = initializeRuntime();
         } catch (UnsatisfiedLinkError e) {
-            runtime = new GraalRuntime() {
-
-                @Override
-                public String getName() {
-                    return "";
-                }
-
-                @Override
-                public <T> T getCapability(Class<T> clazz) {
-                    return null;
-                }
-            };
+            runtime = new InvalidGraalRuntime();
         }
     }
 
     public static <T> T getRequiredCapability(Class<T> clazz) {
         T t = getRuntime().getCapability(clazz);
         if (t == null) {
-            throw new IllegalAccessError("Runtime does not expose required capability " + clazz.getName());
+            String javaHome = System.getProperty("java.home");
+            String vmName = System.getProperty("java.vm.name");
+            StringBuilder errorMessage = new StringBuilder();
+            if (runtime.getClass() == InvalidGraalRuntime.class) {
+                errorMessage.append(String.format("The VM does not support the Graal API.\n"));
+            } else {
+                errorMessage.append(String.format("The VM does not expose required Graal capability %s.\n", clazz.getName()));
+            }
+            errorMessage.append(String.format("Currently used Java home directory is %s.\n", javaHome));
+            errorMessage.append(String.format("Currently used VM configuration is: %s", vmName));
+            throw new UnsupportedOperationException(errorMessage.toString());
         }
         return t;
     }
+
+    private static final class InvalidGraalRuntime implements GraalRuntime {
+
+        @Override
+        public String getName() {
+            return "";
+        }
+
+        @Override
+        public <T> T getCapability(Class<T> clazz) {
+            return null;
+        }
+    }
 }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.ptx.test;
 
+import java.lang.reflect.*;
+
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -35,7 +37,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.ptx.*;
 
 /**
@@ -90,7 +92,12 @@
 
     public static void main(String[] args) {
         BasicPTXTest basicPTXTest = new BasicPTXTest();
-        System.out.println("testAddSnippet: \n" + new String(basicPTXTest.test("testAddSnippet").getTargetCode()));
-        System.out.println("testArraySnippet: \n" + new String(basicPTXTest.test("testArraySnippet").getTargetCode()));
+        Method[] methods = BasicPTXTest.class.getMethods();
+        for (Method m : methods) {
+            if (m.getAnnotation(Test.class) != null) {
+                String name = m.getName() + "Snippet";
+                System.out.println(name + ": \n" + new String(basicPTXTest.test(name).getTargetCode()));
+            }
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -120,9 +120,9 @@
                 PhasePlan phasePlan = getDefaultPhasePlan();
                 phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase);
                 identifyBoxingPhase.apply(graph);
-                Collection<Invoke> hints = new ArrayList<>();
+                Map<Invoke, Double> hints = new HashMap<>();
                 for (Invoke invoke : graph.getInvokes()) {
-                    hints.add(invoke);
+                    hints.put(invoke, 1000d);
                 }
 
                 Assumptions assumptions = new Assumptions(false);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -71,11 +71,15 @@
     protected final Backend backend;
 
     public GraalCompilerTest() {
-        DebugEnvironment.initialize(System.out);
         this.runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class);
         this.backend = Graal.getRequiredCapability(Backend.class);
     }
 
+    @BeforeClass
+    public static void initializeDebgging() {
+        DebugEnvironment.initialize(System.out);
+    }
+
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
         String expectedString = getCanonicalGraphString(expected);
         String actualString = getCanonicalGraphString(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -83,9 +83,9 @@
                 phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase);
                 phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase());
                 identifyBoxingPhase.apply(graph);
-                Collection<Invoke> hints = new ArrayList<>();
+                Map<Invoke, Double> hints = new HashMap<>();
                 for (Invoke invoke : graph.getInvokes()) {
-                    hints.add(invoke);
+                    hints.put(invoke, 1000d);
                 }
 
                 Assumptions assumptions = new Assumptions(false);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -60,9 +60,9 @@
 
     private void test(String snippet) {
         StructuredGraph graph = parseProfiled(snippet);
-        Collection<Invoke> hints = new ArrayList<>();
+        Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
-            hints.add(invoke);
+            hints.put(invoke, 1000d);
         }
         Assumptions assumptions = new Assumptions(false);
         new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -70,9 +70,9 @@
 
     private void test(String snippet) {
         StructuredGraph graph = parse(snippet);
-        Collection<Invoke> hints = new ArrayList<>();
+        Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
-            hints.add(invoke);
+            hints.put(invoke, 1000d);
         }
 
         Assumptions assumptions = new Assumptions(false);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -88,9 +88,9 @@
         for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) {
             n.replaceFirstInput(local, constant);
         }
-        Collection<Invoke> hints = new ArrayList<>();
+        Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
-            hints.add(invoke);
+            hints.put(invoke, 1000d);
         }
         Assumptions assumptions = new Assumptions(false);
         new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.test.ea;
 
 import junit.framework.*;
+import junit.framework.Assert;
 
 import org.junit.Test;
 
@@ -30,7 +31,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -183,12 +183,7 @@
 
     @Test
     public void testInstanceOf() {
-        ReturnNode returnNode = testEscapeAnalysis("testInstanceOfSnippet", null, false);
-        ValueNode result = returnNode.result();
-        Assert.assertTrue(result instanceof ConditionalNode);
-        ConditionalNode conditional = (ConditionalNode) result;
-        Assert.assertTrue(conditional.condition() instanceof LogicConstantNode);
-        Assert.assertEquals(true, ((LogicConstantNode) conditional.condition()).getValue());
+        testEscapeAnalysis("testInstanceOfSnippet", Constant.forInt(1), false);
     }
 
     public boolean testInstanceOfSnippet() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.ea;
+
+import static org.junit.Assert.*;
+
+import java.util.concurrent.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.test.*;
+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.phases.ea.*;
+
+public class IterativeInliningTest extends GraalCompilerTest {
+
+    private StructuredGraph graph;
+
+    public static class TestObject {
+
+        public Callable<Integer> callable;
+
+        public TestObject(Callable<Integer> callable) {
+            this.callable = callable;
+        }
+    }
+
+    public static class TestInt implements Callable<Integer> {
+
+        public int x;
+        public int y;
+
+        public TestInt(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public Integer call() throws Exception {
+            return new Integer(x);
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleSnippet(int b) throws Exception {
+        TestObject a = new TestObject(null);
+        a.callable = new TestInt(b, 9);
+        return a.callable.call();
+    }
+
+    @Test
+    public void testSimple() {
+        ValueNode result = getReturn("testSimpleSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertEquals(graph.getLocal(0), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleReadSnippet(TestObject a, int b) throws Exception {
+        a.callable = new TestInt(b, 9);
+        return a.callable.call();
+    }
+
+    @Test
+    public void testSimpleRead() {
+        ValueNode result = getReturn("testSimpleReadSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertEquals(graph.getLocal(1), result);
+    }
+
+    final ReturnNode getReturn(String snippet) {
+        processMethod(snippet);
+        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        return graph.getNodes(ReturnNode.class).first();
+    }
+
+    private void processMethod(final String snippet) {
+        graph = parse(snippet);
+        new ComputeProbabilityPhase().apply(graph);
+        GraalOptions.PEAReadCache = true;
+        new IterativeInliningPhase(runtime(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.ea;
+
+import static org.junit.Assert.*;
+
+import java.util.concurrent.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.test.*;
+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.phases.ea.*;
+
+public class PEAReadEliminationTest extends GraalCompilerTest {
+
+    private StructuredGraph graph;
+
+    public static Object staticField;
+
+    public static class TestObject implements Callable<Integer> {
+
+        public int x;
+        public int y;
+
+        public TestObject(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public Integer call() throws Exception {
+            return x;
+        }
+    }
+
+    public static class TestObject2 {
+
+        public Object x;
+        public Object y;
+
+        public TestObject2(Object x, Object y) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleSnippet(TestObject a) {
+        a.x = 2;
+        staticField = a;
+        return a.x;
+    }
+
+    @Test
+    public void testSimple() {
+        ValueNode result = getReturn("testSimpleSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertTrue(result.isConstant());
+        assertEquals(2, result.asConstant().asInt());
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleConflictSnippet(TestObject a, TestObject b) {
+        a.x = 2;
+        b.x = 3;
+        staticField = a;
+        return a.x;
+    }
+
+    @Test
+    public void testSimpleConflict() {
+        ValueNode result = getReturn("testSimpleConflictSnippet").result();
+        assertFalse(result.isConstant());
+        assertTrue(result instanceof LoadFieldNode);
+    }
+
+    @SuppressWarnings("all")
+    public static int testParamSnippet(TestObject a, int b) {
+        a.x = b;
+        return a.x;
+    }
+
+    @Test
+    public void testParam() {
+        ValueNode result = getReturn("testParamSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertEquals(graph.getLocal(1), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testMaterializedSnippet(int a) {
+        TestObject obj = new TestObject(a, 0);
+        staticField = obj;
+        return obj.x;
+    }
+
+    @Test
+    public void testMaterialized() {
+        ValueNode result = getReturn("testMaterializedSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertEquals(graph.getLocal(0), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleLoopSnippet(TestObject obj, int a, int b) {
+        obj.x = a;
+        for (int i = 0; i < 10; i++) {
+            staticField = obj;
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testSimpleLoop() {
+        ValueNode result = getReturn("testSimpleLoopSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertEquals(graph.getLocal(1), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testBadLoopSnippet(TestObject obj, int a, int b) {
+        obj.x = a;
+        for (int i = 0; i < 10; i++) {
+            staticField = obj;
+            obj.x = 0;
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testBadLoop() {
+        ValueNode result = getReturn("testBadLoopSnippet").result();
+        assertEquals(1, graph.getNodes(LoadFieldNode.class).count());
+        assertTrue(result instanceof LoadFieldNode);
+    }
+
+    @SuppressWarnings("all")
+    public static int testPhiSnippet(TestObject a, int b) {
+        if (b < 0) {
+            a.x = 1;
+        } else {
+            a.x = 2;
+        }
+        return a.x;
+    }
+
+    @Test
+    public void testPhi() {
+        ValueNode result = getReturn("testPhiSnippet").result();
+        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
+        assertTrue(result instanceof PhiNode);
+        PhiNode phi = (PhiNode) result;
+        assertTrue(phi.valueAt(0).isConstant());
+        assertTrue(phi.valueAt(1).isConstant());
+        assertEquals(1, phi.valueAt(0).asConstant().asInt());
+        assertEquals(2, phi.valueAt(1).asConstant().asInt());
+    }
+
+    @SuppressWarnings("all")
+    public static void testSimpleStoreSnippet(TestObject a, int b) {
+        a.x = b;
+        a.x = b;
+    }
+
+    @Test
+    public void testSimpleStore() {
+        processMethod("testSimpleStoreSnippet");
+        assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
+    }
+
+    final ReturnNode getReturn(String snippet) {
+        processMethod(snippet);
+        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        return graph.getNodes(ReturnNode.class).first();
+    }
+
+    private void processMethod(final String snippet) {
+        graph = parse(snippet);
+        new ComputeProbabilityPhase().apply(graph);
+        Assumptions assumptions = new Assumptions(false);
+        new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
+        GraalOptions.PEAReadCache = true;
+        new PartialEscapeAnalysisPhase(runtime(), assumptions, false).apply(graph);
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Apr 03 14:41:22 2013 +0200
@@ -121,12 +121,16 @@
         }
 
         if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) {
-            new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph);
-            new DeadCodeEliminationPhase().apply(graph);
+            if (GraalOptions.IterativeInlining) {
+                new IterativeInliningPhase(runtime, assumptions, cache, plan, optimisticOpts).apply(graph);
+            } else {
+                new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph);
+                new DeadCodeEliminationPhase().apply(graph);
 
-            if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) {
-                new CanonicalizerPhase(runtime, assumptions).apply(graph);
-                new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph);
+                if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) {
+                    new CanonicalizerPhase(runtime, assumptions).apply(graph);
+                    new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph);
+                }
             }
         }
 
@@ -164,16 +168,16 @@
         }
         new RemoveValueProxyPhase().apply(graph);
 
+        if (GraalOptions.CullFrameStates) {
+            new CullFrameStatesPhase().apply(graph);
+        }
+
         if (GraalOptions.OptCanonicalizer) {
             new CanonicalizerPhase(runtime, assumptions).apply(graph);
         }
 
         new LoweringPhase(target, runtime, assumptions).apply(graph);
 
-        if (GraalOptions.CullFrameStates) {
-            new CullFrameStatesPhase().apply(graph);
-        }
-
         if (GraalOptions.OptFloatingReads) {
             int mark = graph.getMark();
             new FloatingReadPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Wed Apr 03 14:41:22 2013 +0200
@@ -34,18 +34,21 @@
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.virtual.nodes.*;
 
+/**
+ * Builds {@link LIRFrameState}s from {@link FrameState}s.
+ */
 public class DebugInfoBuilder {
 
-    private final NodeMap<Value> nodeOperands;
+    protected final NodeMap<Value> nodeOperands;
 
     public DebugInfoBuilder(NodeMap<Value> nodeOperands) {
         this.nodeOperands = nodeOperands;
     }
 
-    private HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
-    private IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
+    protected HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
+    protected IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
 
-    public LIRFrameState build(FrameState topState, List<StackSlot> lockData, short reason, LabelRef exceptionEdge) {
+    public LIRFrameState build(FrameState topState, short reason, LabelRef exceptionEdge) {
         assert virtualObjects.size() == 0;
         assert objectStates.size() == 0;
 
@@ -65,7 +68,7 @@
             current = current.outerFrameState();
         } while (current != null);
 
-        BytecodeFrame frame = computeFrameForState(topState, lockData);
+        BytecodeFrame frame = computeFrameForState(topState);
 
         VirtualObject[] virtualObjectsArray = null;
         if (virtualObjects.size() != 0) {
@@ -103,43 +106,62 @@
         }
         objectStates.clear();
 
+        return newLIRFrameState(reason, exceptionEdge, frame, virtualObjectsArray);
+    }
+
+    protected LIRFrameState newLIRFrameState(short reason, LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
         return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason);
     }
 
-    private BytecodeFrame computeFrameForState(FrameState state, List<StackSlot> lockDataSlots) {
+    protected BytecodeFrame computeFrameForState(FrameState state) {
         int numLocals = state.localsSize();
         int numStack = state.stackSize();
         int numLocks = state.locksSize();
 
         Value[] values = new Value[numLocals + numStack + numLocks];
-        for (int i = 0; i < numLocals; i++) {
-            values[i] = toValue(state.localAt(i));
-        }
-        for (int i = 0; i < numStack; i++) {
-            values[numLocals + i] = toValue(state.stackAt(i));
-        }
-        for (int i = 0; i < numLocks; i++) {
-            // frames are traversed from the outside in, so the locks for the current frame are at
-            // the end of the lockDataSlots list
-            StackSlot lockData = lockDataSlots.get(lockDataSlots.size() - numLocks + i);
-            values[numLocals + numStack + i] = new MonitorValue(toValue(state.lockAt(i)), lockData, state.lockAt(i) instanceof VirtualObjectNode);
-        }
+        computeLocals(state, numLocals, values);
+        computeStack(state, numLocals, numStack, values);
+        computeLocks(state, values);
 
         BytecodeFrame caller = null;
         if (state.outerFrameState() != null) {
-            // remove the locks that were used for this frame from the lockDataSlots list
-            List<StackSlot> nextLockDataSlots = lockDataSlots.subList(0, lockDataSlots.size() - numLocks);
-            caller = computeFrameForState(state.outerFrameState(), nextLockDataSlots);
-        } else {
-            if (lockDataSlots.size() != numLocks) {
-                throw new BailoutException("unbalanced monitors: found monitor for unknown frame (%d != %d) at %s", lockDataSlots.size(), numLocks, state);
-            }
+            caller = computeFrameForState(state.outerFrameState());
         }
         assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI : "bci == " + state.bci;
         return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
     }
 
-    private Value toValue(ValueNode value) {
+    protected void computeLocals(FrameState state, int numLocals, Value[] values) {
+        for (int i = 0; i < numLocals; i++) {
+            values[i] = computeLocalValue(state, i);
+        }
+    }
+
+    protected Value computeLocalValue(FrameState state, int i) {
+        return toValue(state.localAt(i));
+    }
+
+    protected void computeStack(FrameState state, int numLocals, int numStack, Value[] values) {
+        for (int i = 0; i < numStack; i++) {
+            values[numLocals + i] = computeStackValue(state, i);
+        }
+    }
+
+    protected Value computeStackValue(FrameState state, int i) {
+        return toValue(state.stackAt(i));
+    }
+
+    protected void computeLocks(FrameState state, Value[] values) {
+        for (int i = 0; i < state.locksSize(); i++) {
+            values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i);
+        }
+    }
+
+    protected Value computeLockValue(FrameState state, int i) {
+        return toValue(state.lockAt(i));
+    }
+
+    protected Value toValue(ValueNode value) {
         if (value instanceof VirtualObjectNode) {
             VirtualObjectNode obj = (VirtualObjectNode) value;
             EscapeObjectState state = objectStates.get(obj);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Apr 03 14:41:22 2013 +0200
@@ -63,7 +63,7 @@
     protected final TargetDescription target;
     protected final ResolvedJavaMethod method;
 
-    private final DebugInfoBuilder debugInfoBuilder;
+    protected final DebugInfoBuilder debugInfoBuilder;
 
     protected Block currentBlock;
     private ValueNode currentInstruction;
@@ -76,22 +76,6 @@
     private final BlockMap<FrameState> blockLastState;
 
     /**
-     * The number of currently locked monitors.
-     */
-    private int currentLockCount;
-
-    /**
-     * Mapping from blocks to the number of locked monitors at the end of the block.
-     */
-    private final BlockMap<Integer> blockLastLockCount;
-
-    /**
-     * Contains the lock data slot for each lock depth (so these may be reused within a compiled
-     * method).
-     */
-    private final ArrayList<StackSlot> lockDataSlots;
-
-    /**
      * Checks whether the supplied constant can be used without loading it into a register for store
      * operations, i.e., on the right hand side of a memory access.
      * 
@@ -109,12 +93,15 @@
         this.method = method;
         this.nodeOperands = graph.createNodeMap();
         this.lir = lir;
-        this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands);
-        this.blockLastLockCount = new BlockMap<>(lir.cfg);
-        this.lockDataSlots = new ArrayList<>();
+        this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
         this.blockLastState = new BlockMap<>(lir.cfg);
     }
 
+    @SuppressWarnings("hiding")
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        return new DebugInfoBuilder(nodeOperands);
+    }
+
     @Override
     public TargetDescription target() {
         return target;
@@ -248,7 +235,7 @@
         if (needOnlyOopMaps()) {
             return new LIRFrameState(null, null, null, (short) -1);
         }
-        return debugInfoBuilder.build(state, lockDataSlots.subList(0, currentLockCount), lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge);
+        return debugInfoBuilder.build(state, lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge);
     }
 
     /**
@@ -297,22 +284,10 @@
 
         if (block == lir.cfg.getStartBlock()) {
             assert block.getPredecessorCount() == 0;
-            currentLockCount = 0;
             emitPrologue();
 
         } else {
             assert block.getPredecessorCount() > 0;
-
-            currentLockCount = -1;
-            for (Block pred : block.getPredecessors()) {
-                Integer predLocks = blockLastLockCount.get(pred);
-                if (currentLockCount == -1) {
-                    currentLockCount = predLocks;
-                } else {
-                    assert (predLocks == null && pred.isLoopEnd()) || currentLockCount == predLocks;
-                }
-            }
-
             FrameState fs = null;
 
             for (Block pred : block.getPredecessors()) {
@@ -401,7 +376,6 @@
         // share the frame state that flowed into the loop
         assert blockLastState.get(block) == null || blockLastState.get(block) == lastState;
 
-        blockLastLockCount.put(currentBlock, currentLockCount);
         blockLastState.put(block, lastState);
         currentBlock = null;
 
@@ -480,36 +454,6 @@
         append(new ParametersOp(params));
     }
 
-    /**
-     * Increases the number of currently locked monitors and makes sure that a lock data slot is
-     * available for the new lock.
-     */
-    public void lock() {
-        if (lockDataSlots.size() == currentLockCount) {
-            lockDataSlots.add(frameMap.allocateStackBlock(runtime.getSizeOfLockData(), false));
-        }
-        currentLockCount++;
-    }
-
-    /**
-     * Decreases the number of currently locked monitors.
-     * 
-     * @throws GraalInternalError if the number of currently locked monitors is already zero.
-     */
-    public void unlock() {
-        if (currentLockCount == 0) {
-            throw new GraalInternalError("unmatched locks");
-        }
-        currentLockCount--;
-    }
-
-    /**
-     * @return The lock data slot for the topmost locked monitor.
-     */
-    public StackSlot peekLock() {
-        return lockDataSlots.get(currentLockCount - 1);
-    }
-
     @Override
     public void visitReturn(ReturnNode x) {
         Value operand = Value.ILLEGAL;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Apr 03 14:41:22 2013 +0200
@@ -197,6 +197,7 @@
                 if (inputChanged != null) {
                     inputChanged.inputChanged(this);
                 }
+                assert newInput.usages != null : "not yet added? " + newInput;
                 newInput.usages.add(this);
             }
         }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Apr 03 14:41:22 2013 +0200
@@ -35,6 +35,8 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.*;
 import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -84,6 +86,19 @@
      */
     List<AMD64HotSpotEpilogueOp> epilogueOps = new ArrayList<>(2);
 
+    @SuppressWarnings("hiding")
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        assert runtime().config.basicLockSize == 8;
+        HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long);
+        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+    }
+
+    @Override
+    public StackSlot getLockSlot(int lockDepth) {
+        return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth);
+    }
+
     @Override
     protected void emitPrologue() {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/InstalledCodeExecuteHelperTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class InstalledCodeExecuteHelperTest extends GraalCompilerTest {
+
+    private static final int ITERATIONS = 100000000;
+
+    @Ignore
+    @Test
+    public void test1() throws NoSuchMethodException, SecurityException {
+
+        final Method benchrMethod = InstalledCodeExecuteHelperTest.class.getMethod("bench", long.class, long.class);
+        final ResolvedJavaMethod benchJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(benchrMethod);
+        HotSpotInstalledCode benchCode = (HotSpotInstalledCode) getCode(benchJavaMethod, parse(benchrMethod));
+
+        final Method wrapperMethod = InstalledCodeExecuteHelperTest.class.getMethod("executeWrapper", long.class, long.class, Object.class, Object.class, Object.class);
+        final ResolvedJavaMethod wrapperJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(wrapperMethod);
+        HotSpotInstalledCode wrapperCode = (HotSpotInstalledCode) getCode(wrapperJavaMethod, parse(wrapperMethod));
+
+        final Method fooMethod = InstalledCodeExecuteHelperTest.class.getMethod("foo", Object.class, Object.class, Object.class);
+        final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(fooMethod);
+        HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod));
+
+        System.out.println(wrapperCode.executeVarargs(fooCode.getnmethod(), fooJavaMethod.getMetaspaceMethod(), null, null, null));
+
+        long nmethod = fooCode.getnmethod();
+        long metaspacemethod = fooJavaMethod.getMetaspaceMethod();
+
+        System.out.println("Without replaced InstalledCode.execute:" + bench(nmethod, metaspacemethod));
+
+        System.out.println("WITH replaced InstalledCode.execute:" + benchCode.executeVarargs(nmethod, metaspacemethod));
+
+    }
+
+    public static Long bench(long nmethod, long metaspacemethod) {
+        long start = System.currentTimeMillis();
+
+        for (int i = 0; i < ITERATIONS; i++) {
+            HotSpotInstalledCode.executeHelper(nmethod, metaspacemethod, null, null, null);
+        }
+
+        long end = System.currentTimeMillis();
+        return (end - start);
+    }
+
+    public static Object foo(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) {
+        return 42;
+    }
+
+    public static Object executeWrapper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) {
+        return HotSpotInstalledCode.executeHelper(nmethod, metaspaceMethod, arg1, arg2, arg3);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.virtual.*;
+
+/**
+ * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks.
+ */
+public class HotSpotDebugInfoBuilder extends DebugInfoBuilder {
+
+    private final HotSpotLockStack lockStack;
+
+    public HotSpotDebugInfoBuilder(NodeMap<Value> nodeOperands, HotSpotLockStack lockStack) {
+        super(nodeOperands);
+        this.lockStack = lockStack;
+    }
+
+    public HotSpotLockStack lockStack() {
+        return lockStack;
+    }
+
+    @Override
+    protected Value computeLockValue(FrameState state, int i) {
+        int lockDepth = i;
+        if (state.outerFrameState() != null) {
+            lockDepth = state.outerFrameState().nestedLockDepth();
+        }
+        StackSlot slot = lockStack.makeLockSlot(lockDepth);
+        ValueNode lock = state.lockAt(i);
+        Value object = toValue(lock);
+        boolean eliminated = lock instanceof VirtualObjectNode;
+        return new HotSpotMonitorValue(object, slot, eliminated);
+    }
+
+    @Override
+    protected LIRFrameState newLIRFrameState(short reason, LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
+        return new HotSpotLIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+/**
+ * Extends {@link LIRFrameState} to handle {@link HotSpotMonitorValue}s correctly.
+ */
+class HotSpotLIRFrameState extends LIRFrameState {
+
+    public HotSpotLIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge, short deoptimizationReason) {
+        super(topFrame, virtualObjects, exceptionEdge, deoptimizationReason);
+    }
+
+    @Override
+    protected Value processValue(ValueProcedure proc, Value value) {
+        if (value instanceof HotSpotMonitorValue) {
+            HotSpotMonitorValue monitor = (HotSpotMonitorValue) value;
+            if (processed(monitor.getOwner())) {
+                monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
+            }
+            return value;
+        } else {
+            return super.processValue(proc, value);
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -42,4 +43,9 @@
     void emitTailcall(Value[] args, Value address);
 
     void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
+
+    /**
+     * Gets a stack slot for a lock at a given lock nesting depth.
+     */
+    StackSlot getLockSlot(int lockDepth);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * Manages allocation and re-use of lock slots in a scoped manner. The slots are used in HotSpot's
+ * lightweight locking mechanism to store the mark word of an object being locked.
+ */
+public class HotSpotLockStack {
+
+    private StackSlot[] locks;
+    private final FrameMap frameMap;
+    private final Kind slotKind;
+
+    public HotSpotLockStack(FrameMap frameMap, Kind slotKind) {
+        this.frameMap = frameMap;
+        this.slotKind = slotKind;
+    }
+
+    /**
+     * Gets a stack slot for a lock at a given lock nesting depth, allocating it first if necessary.
+     */
+    public StackSlot makeLockSlot(int lockDepth) {
+        if (locks == null) {
+            locks = new StackSlot[lockDepth + 1];
+        } else if (locks.length < lockDepth + 1) {
+            locks = Arrays.copyOf(locks, lockDepth + 1);
+        }
+        if (locks[lockDepth] == null) {
+            locks[lockDepth] = frameMap.allocateSpillSlot(slotKind);
+        }
+        return locks[lockDepth];
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Apr 03 14:41:22 2013 +0200
@@ -44,6 +44,7 @@
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.printer.*;
@@ -76,6 +77,8 @@
 
     private boolean quietMeterAndTime;
 
+    private long compilerStartTime;
+
     public VMToCompilerImpl(HotSpotGraalRuntime compiler) {
         this.graalRuntime = compiler;
 
@@ -196,6 +199,95 @@
             t.setDaemon(true);
             t.start();
         }
+
+        if (GraalOptions.BenchmarkDynamicCounters) {
+            System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, " starting =====", " PASSED in ", "\n")));
+            System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, "Iteration ~ (~s) begins: ", "Iteration ~ (~s) ends:   ", "\n")));
+            DynamicCounterNode.excludedClassPrefix = "Lcom/oracle/graal/";
+            DynamicCounterNode.enabled = true;
+        }
+        if (GraalOptions.GenericDynamicCounters) {
+            DynamicCounterNode.enabled = true;
+        }
+        compilerStartTime = System.nanoTime();
+    }
+
+    private final class BenchmarkCountersOutputStream extends CallbackOutputStream {
+
+        private long startTime;
+        private boolean waitingForEnd;
+
+        private BenchmarkCountersOutputStream(PrintStream delegate, String... patterns) {
+            super(delegate, patterns);
+        }
+
+        @Override
+        protected void patternFound(int index) {
+            switch (index) {
+                case 0:
+                    startTime = System.nanoTime();
+                    DynamicCounterNode.clear();
+                    break;
+                case 1:
+                    waitingForEnd = true;
+                    break;
+                case 2:
+                    if (waitingForEnd) {
+                        waitingForEnd = false;
+                        DynamicCounterNode.dump(delegate, (System.nanoTime() - startTime) / 1000000000d);
+                    }
+                    break;
+            }
+        }
+    }
+
+    public abstract static class CallbackOutputStream extends OutputStream {
+
+        protected final PrintStream delegate;
+        private final byte[][] patterns;
+        private final int[] positions;
+
+        public CallbackOutputStream(PrintStream delegate, String... patterns) {
+            this.delegate = delegate;
+            this.positions = new int[patterns.length];
+            this.patterns = new byte[patterns.length][];
+            for (int i = 0; i < patterns.length; i++) {
+                this.patterns[i] = patterns[i].getBytes();
+            }
+        }
+
+        protected abstract void patternFound(int index);
+
+        @Override
+        public void write(int b) throws IOException {
+            try {
+                delegate.write(b);
+                for (int i = 0; i < patterns.length; i++) {
+                    int j = positions[i];
+                    byte[] cs = patterns[i];
+                    byte patternChar = cs[j];
+                    if (patternChar == '~' && Character.isDigit(b)) {
+                        // nothing to do...
+                    } else {
+                        if (patternChar == '~') {
+                            patternChar = cs[++positions[i]];
+                        }
+                        if (b == patternChar) {
+                            positions[i]++;
+                        } else {
+                            positions[i] = 0;
+                        }
+                    }
+                    if (positions[i] == patterns[i].length) {
+                        positions[i] = 0;
+                        patternFound(i);
+                    }
+                }
+            } catch (RuntimeException e) {
+                e.printStackTrace(delegate);
+                throw e;
+            }
+        }
     }
 
     /**
@@ -281,6 +373,7 @@
         }
         System.gc();
         phaseTransition("bootstrap2");
+
     }
 
     private MetricRateInPhase parsedBytecodesPerSecond;
@@ -353,6 +446,9 @@
         }
 
         SnippetCounter.printGroups(TTY.out().out());
+        if (GraalOptions.GenericDynamicCounters) {
+            DynamicCounterNode.dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d);
+        }
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -51,6 +51,10 @@
         return isDefault;
     }
 
+    public long getnmethod() {
+        return nmethod;
+    }
+
     @Override
     public ResolvedJavaMethod getMethod() {
         return method;
@@ -104,4 +108,8 @@
     public byte[] getCode() {
         return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod);
     }
+
+    public static Object executeHelper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) {
+        return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(metaspaceMethod, nmethod, arg1, arg2, arg3);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, 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 com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Represents lock information in the debug information.
+ */
+public final class HotSpotMonitorValue extends Value {
+
+    private static final long serialVersionUID = 8241681800464483691L;
+
+    private Value owner;
+    private final StackSlot slot;
+    private final boolean eliminated;
+
+    public HotSpotMonitorValue(Value owner, StackSlot slot, boolean eliminated) {
+        super(Kind.Illegal);
+        this.owner = owner;
+        this.slot = slot;
+        this.eliminated = eliminated;
+    }
+
+    public Value getOwner() {
+        return owner;
+    }
+
+    public void setOwner(Value newOwner) {
+        this.owner = newOwner;
+    }
+
+    public Value getSlot() {
+        return slot;
+    }
+
+    public boolean isEliminated() {
+        return eliminated;
+    }
+
+    @Override
+    public String toString() {
+        return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]";
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Apr 03 14:41:22 2013 +0200
@@ -73,6 +73,10 @@
         return holder;
     }
 
+    public long getMetaspaceMethod() {
+        return metaspaceMethod;
+    }
+
     /**
      * Gets the address of the C++ Method object for this method.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Apr 03 14:41:22 2013 +0200
@@ -487,11 +487,6 @@
     }
 
     @Override
-    public int getSizeOfLockData() {
-        return config.basicLockSize;
-    }
-
-    @Override
     public boolean constantEquals(Constant x, Constant y) {
         return x.equals(y);
     }
@@ -529,8 +524,10 @@
         Kind wordKind = graalRuntime.getTarget().wordKind;
         if (n instanceof ArrayLengthNode) {
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
-            SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.array());
-            graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength);
+            ValueNode array = arrayLengthNode.array();
+            ReadNode arrayLengthRead = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
+            arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array));
+            graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
         } else if (n instanceof Invoke) {
             Invoke invoke = (Invoke) n;
             if (invoke.callTarget() instanceof MethodCallTargetNode) {
@@ -566,9 +563,6 @@
                             graph.addAfterFixed(metaspaceMethod, compiledEntry);
                         }
                     }
-                } else if (callTarget.invokeKind() == InvokeKind.Special || callTarget.invokeKind() == InvokeKind.Static) {
-                    loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
-                                    callTarget.invokeKind()));
                 }
 
                 if (loweredCallTarget == null) {
@@ -611,12 +605,18 @@
             FixedWithNextNode first = memoryWrite;
 
             if (field.getKind() == Kind.Object && !memoryWrite.value().objectStamp().alwaysNull()) {
-                WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(memoryWrite.object(), null, memoryWrite.location(), true));
-                WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(memoryWrite.object(), memoryWrite.value(), memoryWrite.location(), false));
-                graph.addBeforeFixed(memoryWrite, writeBarrierPre);
-                graph.addAfterFixed(memoryWrite, writeBarrierPost);
-                first = writeBarrierPre;
-                last = writeBarrierPost;
+                if (config.useG1GC) {
+                    WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(memoryWrite.object(), null, memoryWrite.location(), true));
+                    WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(memoryWrite.object(), memoryWrite.value(), memoryWrite.location(), false));
+                    graph.addBeforeFixed(memoryWrite, writeBarrierPre);
+                    graph.addAfterFixed(memoryWrite, writeBarrierPost);
+                    first = writeBarrierPre;
+                    last = writeBarrierPost;
+                } else {
+                    FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(memoryWrite.object()));
+                    graph.addAfterFixed(memoryWrite, writeBarrier);
+                    last = writeBarrier;
+                }
             }
             if (storeField.isVolatile()) {
                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
@@ -631,14 +631,25 @@
             LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
             if (expected.kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) {
                 ResolvedJavaType type = cas.object().objectStamp().type();
-                WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true));
-                graph.addBeforeFixed(cas, writeBarrierPre);
                 if (type != null && !type.isArray() && !MetaUtil.isJavaLangObject(type)) {
-                    WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, false));
-                    graph.addAfterFixed(cas, writeBarrierPost);
+                    // Use a field write barrier since it's not an array store
+                    if (config.useG1GC) {
+                        WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true));
+                        WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, false));
+                        graph.addBeforeFixed(cas, writeBarrierPre);
+                        graph.addAfterFixed(cas, writeBarrierPost);
+                    } else {
+                        graph.addAfterFixed(cas, graph.add(new FieldWriteBarrier(cas.object())));
+                    }
                 } else {
-                    WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, true));
-                    graph.addAfterFixed(cas, writeBarrierPost);
+                    // This may be an array store so use an array write barrier
+                    if (config.useG1GC) {
+                        WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true));
+                        graph.addBeforeFixed(cas, writeBarrierPre);
+                        graph.addAfterFixed(cas, graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, true)));
+                    } else {
+                        graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location)));
+                    }
                 }
             }
         } else if (n instanceof LoadIndexedNode) {
@@ -682,10 +693,14 @@
             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 
             if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) {
-                WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(array, null, arrayLocation, true));
-                graph.addBeforeFixed(memoryWrite, writeBarrierPre);
-                WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(array, value, arrayLocation, true));
-                graph.addAfterFixed(memoryWrite, writeBarrierPost);
+                if (config.useG1GC) {
+                    WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(array, null, arrayLocation, true));
+                    graph.addBeforeFixed(memoryWrite, writeBarrierPre);
+                    WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(array, value, arrayLocation, true));
+                    graph.addAfterFixed(memoryWrite, writeBarrierPost);
+                } else {
+                    graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation)));
+                }
             }
         } else if (n instanceof UnsafeLoadNode) {
             UnsafeLoadNode load = (UnsafeLoadNode) n;
@@ -705,12 +720,25 @@
             graph.replaceFixedWithFixed(store, write);
             if (write.value().kind() == Kind.Object && !write.value().objectStamp().alwaysNull()) {
                 ResolvedJavaType type = object.objectStamp().type();
-                WriteBarrierPre writeBarrierPre = new WriteBarrierPre(object, null, location, true);
-                graph.addBeforeFixed(write, graph.add(writeBarrierPre));
+                // WriteBarrier writeBarrier;
                 if (type != null && !type.isArray() && !MetaUtil.isJavaLangObject(type)) {
-                    graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, false)));
+                    // Use a field write barrier since it's not an array store
+                    if (config.useG1GC) {
+                        WriteBarrierPre writeBarrierPre = new WriteBarrierPre(object, null, location, true);
+                        graph.addBeforeFixed(write, graph.add(writeBarrierPre));
+                        graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, false)));
+                    } else {
+                        graph.addAfterFixed(write, graph.add(new FieldWriteBarrier(object)));
+                    }
                 } else {
-                    graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, true)));
+                    // This may be an array store so use an array write barrier
+                    if (config.useG1GC) {
+                        WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(object, null, location, true));
+                        graph.addBeforeFixed(write, writeBarrierPre);
+                        graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, true)));
+                    } else {
+                        graph.addAfterFixed(write, graph.add(new ArrayWriteBarrier(object, location)));
+                    }
                 }
             }
         } else if (n instanceof LoadHubNode) {
@@ -743,12 +771,14 @@
             monitorSnippets.lower((MonitorEnterNode) n, tool);
         } else if (n instanceof MonitorExitNode) {
             monitorSnippets.lower((MonitorExitNode) n, tool);
-        } else if (n instanceof SerialWriteBarrierPost) {
-            writeBarrierSnippets.lower((SerialWriteBarrierPost) n, tool);
-        } else if (n instanceof G1WriteBarrierPre) {
-            writeBarrierSnippets.lower((G1WriteBarrierPre) n, tool);
-        } else if (n instanceof G1WriteBarrierPost) {
-            writeBarrierSnippets.lower((G1WriteBarrierPost) n, tool);
+        } else if (n instanceof FieldWriteBarrier) {
+            writeBarrierSnippets.lower((FieldWriteBarrier) n, tool);
+        } else if (n instanceof ArrayWriteBarrier) {
+            writeBarrierSnippets.lower((ArrayWriteBarrier) n, tool);
+        } else if (n instanceof WriteBarrierPre) {
+            writeBarrierSnippets.lower((WriteBarrierPre) n, tool);
+        } else if (n instanceof WriteBarrierPost) {
+            writeBarrierSnippets.lower((WriteBarrierPost) n, tool);
         } else if (n instanceof TLABAllocateNode) {
             newObjectSnippets.lower((TLABAllocateNode) n, tool);
         } else if (n instanceof InitializeObjectNode) {
@@ -773,10 +803,6 @@
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
     }
 
-    private SafeReadNode safeReadArrayLength(ValueNode array) {
-        return safeRead(array.graph(), Kind.Int, array, config.arrayLengthOffset, StampFactory.positiveInt());
-    }
-
     private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) n.graph();
         ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array()));
@@ -786,10 +812,6 @@
         return guard;
     }
 
-    private static SafeReadNode safeRead(Graph graph, Kind kind, ValueNode value, int offset, Stamp stamp) {
-        return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp));
-    }
-
     public ResolvedJavaType lookupJavaType(Class<?> clazz) {
         return HotSpotResolvedObjectType.fromClass(clazz);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public final class ArrayWriteBarrier extends FixedWithNextNode implements Lowerable {
+
+    @Input private ValueNode object;
+    @Input private LocationNode location;
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public LocationNode getLocation() {
+        return location;
+    }
+
+    public ArrayWriteBarrier(ValueNode object, LocationNode location) {
+        super(StampFactory.forVoid());
+        this.object = object;
+        this.location = location;
+    }
+
+    public void lower(LoweringTool generator) {
+        generator.getRuntime().lower(this, generator);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
@@ -37,15 +38,25 @@
  * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer
  * check on the object.
  */
-public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter {
+public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MonitorReference {
 
     private final boolean eliminated;
 
+    private int lockDepth = -1;
+
     public BeginLockScopeNode(boolean eliminated) {
         super(StampFactory.forWord());
         this.eliminated = eliminated;
     }
 
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
     @Override
     public boolean hasSideEffect() {
         return false;
@@ -58,11 +69,12 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        gen.lock();
-        StackSlot lockData = gen.peekLock();
+        assert lockDepth != -1;
         assert stateAfter() != null;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        StackSlot slot = hsGen.getLockSlot(lockDepth);
         if (!eliminated) {
-            Value result = gen.emitLea(lockData);
+            Value result = gen.emitLea(slot);
             gen.setResult(this, result);
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,26 +22,42 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}.
  */
-public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable {
+public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable, MonitorReference {
+
+    private int lockDepth = -1;
 
     public CurrentLockNode() {
         super(StampFactory.forWord());
     }
 
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
     @Override
     public void generate(LIRGenerator gen) {
+        assert lockDepth != -1;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        StackSlot slot = hsGen.getLockSlot(lockDepth);
         // The register allocator cannot handle stack -> register moves so we use an LEA here
-        Value result = gen.emitMove(gen.emitLea(gen.peekLock()));
+        Value result = gen.emitMove(gen.emitLea(slot));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -50,7 +50,6 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        gen.unlock();
     }
 
     @NodeIntrinsic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,45 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public final class FieldWriteBarrier extends FixedWithNextNode implements Lowerable {
+
+    @Input private ValueNode object;
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public FieldWriteBarrier(ValueNode object) {
+        super(StampFactory.forVoid());
+        this.object = object;
+    }
+
+    public void lower(LoweringTool generator) {
+        generator.getRuntime().lower(this, generator);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPost.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +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.nodes;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class G1WriteBarrierPost extends WriteBarrierPost implements Lowerable {
-
-    @Input private ValueNode object;
-    @Input private ValueNode value;
-    @Input private LocationNode location;
-    private final boolean precise;
-
-    @Override
-    public ValueNode getObject() {
-        return object;
-    }
-
-    @Override
-    public ValueNode getValue() {
-        return value;
-    }
-
-    @Override
-    public LocationNode getLocation() {
-        return location;
-    }
-
-    @Override
-    public boolean usePrecise() {
-        return precise;
-    }
-
-    public G1WriteBarrierPost(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
-        this.object = object;
-        this.value = value;
-        this.location = location;
-        this.precise = precise;
-    }
-
-    @Override
-    public void lower(LoweringTool generator) {
-        generator.getRuntime().lower(this, generator);
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPre.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +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.nodes;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public final class G1WriteBarrierPre extends WriteBarrierPre implements Lowerable {
-
-    @Input private ValueNode object;
-    @Input private LocationNode location;
-    @Input private ValueNode expectedObject;
-    private final boolean doLoad;
-
-    @Override
-    public ValueNode getObject() {
-        return object;
-    }
-
-    @Override
-    public ValueNode getExpectedObject() {
-        return expectedObject;
-    }
-
-    @Override
-    public boolean doLoad() {
-        return doLoad;
-    }
-
-    @Override
-    public LocationNode getLocation() {
-        return location;
-    }
-
-    public G1WriteBarrierPre(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) {
-        this.object = object;
-        this.doLoad = doLoad;
-        this.location = location;
-        this.expectedObject = expectedObject;
-    }
-
-    @Override
-    public void lower(LoweringTool generator) {
-        generator.getRuntime().lower(this, generator);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+public class HotSpotInstalledCodeExecuteNode extends AbstractCallNode implements Lowerable {
+
+    @Input private final ValueNode targetAddress;
+    @Input private final ValueNode metaspaceObject;
+    private final Class[] signature;
+
+    public HotSpotInstalledCodeExecuteNode(Kind kind, ValueNode targetAddress, ValueNode metaspaceObject, Class[] signature, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+        super(StampFactory.forKind(kind), new ValueNode[]{arg1, arg2, arg3});
+        this.targetAddress = targetAddress;
+        this.metaspaceObject = metaspaceObject;
+        this.signature = signature;
+    }
+
+    @Override
+    public Object[] getLocationIdentities() {
+        return new Object[]{LocationNode.ANY_LOCATION};
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        replaceWithInvoke(tool);
+    }
+
+    private InvokeNode replaceWithInvoke(LoweringTool tool) {
+        InvokeNode invoke = createInvoke(tool);
+        ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke);
+        return invoke;
+    }
+
+    protected InvokeNode createInvoke(LoweringTool tool) {
+        ResolvedJavaMethod method = null;
+        try {
+            method = tool.getRuntime().lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class));
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException();
+        }
+        ResolvedJavaType[] signatureTypes = new ResolvedJavaType[signature.length];
+        for (int i = 0; i < signature.length; i++) {
+            signatureTypes[i] = tool.getRuntime().lookupJavaType(signature[i]);
+        }
+        HotSpotIndirectCallTargetNode callTarget = graph().add(
+                        new HotSpotIndirectCallTargetNode(metaspaceObject, targetAddress, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall));
+        InvokeNode invoke = graph().add(new InvokeNode(callTarget, 0));
+        invoke.setStateAfter(stateAfter());
+        return invoke;
+    }
+
+    public static Object placeholder(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) {
+        return 1;
+    }
+
+    @NodeIntrinsic
+    public static native <T> T call(@ConstantNodeParameter Kind kind, Word targetAddress, long metaspaceObject, @ConstantNodeParameter Class[] signature, Object arg1, Object arg2, Object arg3);
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Wed Apr 03 14:41:22 2013 +0200
@@ -26,16 +26,19 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Node implementing a call to HotSpot's {@code graal_monitorexit} stub.
  */
-public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable {
+public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable, MonitorReference {
 
     @Input private final ValueNode object;
+    private int lockDepth;
     public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class);
 
     public MonitorExitStubCall(ValueNode object) {
@@ -43,10 +46,21 @@
         this.object = object;
     }
 
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
     @Override
     public void generate(LIRGenerator gen) {
+        assert lockDepth != -1;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        StackSlot slot = hsGen.getLockSlot(lockDepth);
         RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT);
-        gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(gen.peekLock()));
+        gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(slot));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrierPost.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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.nodes;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class SerialWriteBarrierPost extends WriteBarrierPost implements Lowerable {
-
-    @Input private ValueNode object;
-    @Input private LocationNode location;
-    private final boolean usePrecise;
-
-    public SerialWriteBarrierPost(ValueNode object, LocationNode location, boolean usePrecise) {
-        this.object = object;
-        this.location = location;
-        this.usePrecise = usePrecise;
-    }
-
-    @Override
-    public ValueNode getObject() {
-        return object;
-    }
-
-    @Override
-    public LocationNode getLocation() {
-        return location;
-    }
-
-    @Override
-    public boolean usePrecise() {
-        return usePrecise;
-    }
-
-    @Override
-    public void lower(LoweringTool generator) {
-        generator.getRuntime().lower(this, generator);
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,18 +22,15 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
-
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
-public class WriteBarrierPost extends WriteBarrier implements Lowerable {
+public final class WriteBarrierPost extends FixedWithNextNode implements Lowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode value;
-    @Input private ValueNode index;
     @Input private LocationNode location;
     private final boolean precise;
 
@@ -53,45 +50,15 @@
         return precise;
     }
 
-    public WriteBarrierPost() {
-        this.precise = false;
-    }
-
-    public WriteBarrierPost(ValueNode object, ValueNode value, ValueNode index) {
-        this.object = object;
-        this.value = value;
-        this.index = index;
-        this.precise = true;
-        this.location = null;
-    }
-
     public WriteBarrierPost(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
+        super(StampFactory.forVoid());
         this.object = object;
         this.value = value;
         this.location = location;
         this.precise = precise;
     }
 
-    @Override
     public void lower(LoweringTool generator) {
-        StructuredGraph graph = (StructuredGraph) this.graph();
-        if (location == null) { // Come from array copy intrinsic
-            LocationNode arrayLocation = IndexedLocationNode.create(LocationNode.getArrayLocation(Kind.Object), Kind.Object, arrayBaseOffset(Kind.Object), index, graph, arrayIndexScale(Kind.Object));
-            if (useG1GC()) {
-                graph.replaceFixedWithFixed(this, graph().add(new G1WriteBarrierPost(object, value, arrayLocation, true)));
-            } else {
-                graph.replaceFixedWithFixed(this, graph().add(new SerialWriteBarrierPost(object, arrayLocation, true)));
-            }
-        } else { // Normal WriteBarrier
-            assert location != null;
-            if (useG1GC()) {
-                graph.replaceFixedWithFixed(this, graph().add(new G1WriteBarrierPost(object, value, location, precise)));
-            } else {
-                graph.replaceFixedWithFixed(this, graph().add(new SerialWriteBarrierPost(object, location, precise)));
-            }
-        }
+        generator.getRuntime().lower(this, generator);
     }
-
-    @NodeIntrinsic
-    public static native void arrayCopyWriteBarrier(Object array, Object value, int index);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
-
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
-public class WriteBarrierPre extends WriteBarrier implements Lowerable {
+public final class WriteBarrierPre extends FixedWithNextNode implements Lowerable {
 
     @Input private ValueNode object;
     @Input private LocationNode location;
@@ -51,25 +50,16 @@
         return location;
     }
 
-    public WriteBarrierPre() {
-        this.doLoad = false;
-    }
-
     public WriteBarrierPre(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) {
+        super(StampFactory.forVoid());
         this.object = object;
         this.doLoad = doLoad;
         this.location = location;
         this.expectedObject = expectedObject;
     }
 
-    @Override
     public void lower(LoweringTool generator) {
-        StructuredGraph graph = (StructuredGraph) this.graph();
-        if (useG1GC()) {
-            graph.replaceFixedWithFixed(this, graph().add(new G1WriteBarrierPre(getObject(), getExpectedObject(), getLocation(), doLoad())));
-        } else {
-            graph.removeFixed(this);
-        }
+        generator.getRuntime().lower(this, generator);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
@@ -88,21 +87,6 @@
         new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph);
     }
 
-    private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) {
-        for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) {
-            if (invoke.methodCallTarget().targetMethod() != targetMethod) {
-                throw new GraalInternalError("unexpected invoke in arraycopy snippet");
-            }
-            if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) {
-                InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci));
-                newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI)));
-                snippetGraph.replaceFixedWithFixed(invoke, newInvoke);
-            } else {
-                assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke;
-            }
-        }
-    }
-
     @Override
     protected StructuredGraph getSnippetGraph(LoweringTool tool) {
         if (!GraalOptions.IntrinsifyArrayCopy) {
@@ -115,7 +99,7 @@
             snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Snippet.class)).copy();
             assert snippetGraph != null : "ArrayCopySnippets should be installed";
 
-            replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci());
+            replaceSnippetInvokes(snippetGraph);
         } else {
             assert snippetGraph != null : "ArrayCopySnippets should be installed";
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Wed Apr 03 14:41:22 2013 +0200
@@ -37,7 +37,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
 
@@ -236,8 +236,9 @@
         }
     }
 
+    // Does NOT perform store checks
     @Snippet
-    private static void arrayObjectCopy(Object src, int srcPos, Object dest, int destPos, int length) {
+    public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
         objectCounter.inc();
         checkNonNull(src);
         checkNonNull(dest);
@@ -246,49 +247,45 @@
         int header = arrayBaseOffset(Kind.Object);
         if (src == dest && srcPos < destPos) { // bad aliased case
             long start = (long) (length - 1) * scale;
-            int j = length - 1;
             for (long i = start; i >= 0; i -= scale) {
                 Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object);
                 DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a);
-                WriteBarrierPost.arrayCopyWriteBarrier(dest, a, j);
-                j--;
             }
         } else {
             long end = (long) length * scale;
-            int j = 0;
             for (long i = 0; i < end; i += scale) {
                 Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object);
                 DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a);
-                WriteBarrierPost.arrayCopyWriteBarrier(dest, a, j);
-                j++;
+
+            }
+        }
+        if (length > 0) {
+            int cardShift = cardTableShift();
+            long cardStart = cardTableStart();
+            long dstAddr = GetObjectAddressNode.get(dest);
+            long start = (dstAddr + header + (long) destPos * scale) >>> cardShift;
+            long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift;
+            long count = end - start + 1;
+            while (count-- > 0) {
+                DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean);
             }
         }
     }
 
-    // Does NOT perform store checks
-    @Snippet
-    public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
-        arrayObjectCopy(src, srcPos, dest, destPos, length);
-    }
-
     @Snippet
     public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
+
+        // loading the hubs also checks for nullness
         Word srcHub = loadHub(src);
         Word destHub = loadHub(dest);
+
         int layoutHelper = checkArrayType(srcHub);
-        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
-        final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0);
         if (srcHub.equal(destHub) && src != dest) {
             probability(FAST_PATH_PROBABILITY);
+
             checkLimits(src, srcPos, dest, destPos, length);
-            if (isObjectArray) {
-                genericObjectExactCallCounter.inc();
-                probability(FAST_PATH_PROBABILITY);
-                arrayObjectCopy(src, srcPos, dest, destPos, length);
-            } else {
-                genericPrimitiveCallCounter.inc();
-                arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper);
-            }
+
+            arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper);
         } else {
             genericObjectCallCounter.inc();
             System.arraycopy(src, srcPos, dest, destPos, length);
@@ -316,11 +313,29 @@
             srcOffset = srcOffset.add(1);
         }
         while (destOffset.belowThan(destEnd)) {
-            Word word = srcOffset.readWord(0, UNKNOWN_LOCATION);
-            destOffset.writeWord(0, word, ANY_LOCATION);
+            destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION);
             destOffset = destOffset.add(wordSize());
             srcOffset = srcOffset.add(wordSize());
         }
+
+        if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) {
+            genericPrimitiveCallCounter.inc();
+
+        } else {
+            probability(LIKELY_PROBABILITY);
+            genericObjectExactCallCounter.inc();
+
+            if (length > 0) {
+                int cardShift = cardTableShift();
+                long cardStart = cardTableStart();
+                Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart));
+                Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart));
+                while (destCardOffset.belowOrEqual(destCardEnd)) {
+                    DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean);
+                    destCardOffset = destCardOffset.add(1);
+                }
+            }
+        }
     }
 
     private static final SnippetCounter.Group checkCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy checkInputs") : null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java	Wed Apr 03 14:41:22 2013 +0200
@@ -81,9 +81,8 @@
             }
             exactHit.inc();
         }
-        /**
-         * make sure that the unsafeCast is done *after* the check above,
-         * cf. {@link ReadAfterCheckCast}*/
+        /* make sure that the unsafeCast is done *after* the check above,
+         * cf. ReadAfterCheckCast */
         BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic());
         return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeIntrinsics.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.replacements;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.replacements.*;
+
+@ServiceProvider(ReplacementsProvider.class)
+public class HotSpotInstalledCodeIntrinsics implements ReplacementsProvider {
+
+    @Override
+    public void installReplacements(ReplacementsInstaller installer) {
+        if (GraalOptions.IntrinsifyInstalledCodeMethods) {
+            installer.installSubstitutions(HotSpotInstalledCodeSubstitutions.class);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeSubstitutions.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.word.*;
+
+@ClassSubstitution(HotSpotInstalledCode.class)
+public class HotSpotInstalledCodeSubstitutions {
+
+    @MethodSubstitution
+    public static Object executeHelper(long nmethod, long metaspaceMethod, final Object arg1, final Object arg2, final Object arg3) {
+        final int verifiedEntryPointOffset = HotSpotSnippetUtils.verifiedEntryPointOffset();
+        final Word callTarget = Word.unsigned(nmethod).readWord(verifiedEntryPointOffset);
+        return HotSpotInstalledCodeExecuteNode.call(Kind.Object, callTarget, metaspaceMethod, getSignature(), arg1, arg2, arg3);
+    }
+
+    @Fold
+    private static Class[] getSignature() {
+        return new Class[]{Object.class, Object.class, Object.class};
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Wed Apr 03 14:41:22 2013 +0200
@@ -594,4 +594,9 @@
 
         return IdentityHashCodeStubCall.call(x);
     }
+
+    @Fold
+    public static int verifiedEntryPointOffset() {
+        return config().nmethodEntryOffset;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Apr 03 14:41:22 2013 +0200
@@ -451,6 +451,9 @@
                     BeginLockScopeNode begin = (BeginLockScopeNode) n;
                     begin.setStateAfter(stateAfter);
                 }
+                if (n instanceof MonitorReference) {
+                    ((MonitorReference) n).setLockDepth(monitorenterNode.getLockDepth());
+                }
             }
         }
 
@@ -474,6 +477,9 @@
                     EndLockScopeNode end = (EndLockScopeNode) n;
                     end.setStateAfter(stateAfter);
                 }
+                if (n instanceof MonitorReference) {
+                    ((MonitorReference) n).setLockDepth(monitorexitNode.getLockDepth());
+                }
             }
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Apr 03 14:41:22 2013 +0200
@@ -136,6 +136,7 @@
                     @ConstantParameter("alignment") int alignment,
                     @ConstantParameter("headerSize") int headerSize,
                     @ConstantParameter("log2ElementSize") int log2ElementSize,
+                    @ConstantParameter("fillContents") boolean fillContents,
                     @ConstantParameter("type") ResolvedJavaType type) {
         if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
             probability(DEOPT_PATH_PROBABILITY);
@@ -144,7 +145,7 @@
         }
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
         Word memory = TLABAllocateNode.allocateVariableSize(allocationSize);
-        return InitializeArrayNode.initialize(memory, length, allocationSize, type, true, false);
+        return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents, false);
     }
 
     /**
@@ -240,7 +241,7 @@
             allocate = snippet("allocate", int.class);
             initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class);
             initializeArray = snippet("initializeArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class);
-            allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class);
+            allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, boolean.class, ResolvedJavaType.class);
             newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class);
         }
 
@@ -299,7 +300,8 @@
                 InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked()));
                 graph.replaceFixedWithFixed(newArrayNode, initializeNode);
             } else {
-                Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("type", arrayType);
+                Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("fillContents",
+                                newArrayNode.fillContents()).add("type", arrayType);
                 Arguments arguments = new Arguments().add("length", lengthNode);
                 SnippetTemplate template = cache.get(key, assumptions);
                 Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -122,7 +122,7 @@
                     ValueNode[] state = new ValueNode[fields.length];
                     final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
                     for (int i = 0; i < fields.length; i++) {
-                        state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i]));
+                        state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
                     }
 
                     final StructuredGraph structuredGraph = (StructuredGraph) graph();
@@ -130,7 +130,7 @@
 
                         public void run() {
                             for (LoadFieldNode load : loads) {
-                                structuredGraph.addBeforeFixed(ObjectCloneNode.this, load);
+                                structuredGraph.addBeforeFixed(ObjectCloneNode.this, structuredGraph.add(load));
                             }
                         }
                     });
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Wed Apr 03 14:41:22 2013 +0200
@@ -40,7 +40,7 @@
 public class WriteBarrierSnippets implements Snippets {
 
     @Snippet
-    public static void g1WriteBarrierPre(@Parameter("object") Object obj, @Parameter("expectedObject") Object expobj, @Parameter("location") Object location,
+    public static void g1PreWriteBarrier(@Parameter("object") Object obj, @Parameter("expectedObject") Object expobj, @Parameter("location") Object location,
                     @ConstantParameter("doLoad") boolean doLoad) {
         Word thread = thread();
         Object object = FixedValueAnchorNode.getObject(obj);
@@ -48,9 +48,11 @@
         Word field = (Word) Word.fromArray(object, location);
         Word previousOop = (Word) Word.fromObject(expectedObject);
         byte markingValue = thread.readByte(HotSpotSnippetUtils.g1SATBQueueMarkingOffset());
+
         Word bufferAddress = thread.readWord(HotSpotSnippetUtils.g1SATBQueueBufferOffset());
         Word indexAddress = thread.add(HotSpotSnippetUtils.g1SATBQueueIndexOffset());
         Word indexValue = indexAddress.readWord(0);
+
         if (markingValue != (byte) 0) {
             if (doLoad) {
                 previousOop = field.readWord(0);
@@ -63,13 +65,14 @@
                     indexAddress.writeWord(0, nextIndex);
                 } else {
                     WriteBarrierPreStubCall.call(previousOop);
+
                 }
             }
         }
     }
 
     @Snippet
-    public static void g1WriteBarrierPost(@Parameter("object") Object obj, @Parameter("value") Object value, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) {
+    public static void g1PostWriteBarrier(@Parameter("object") Object obj, @Parameter("value") Object value, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) {
         Word thread = thread();
         Object object = FixedValueAnchorNode.getObject(obj);
         Object wrObject = FixedValueAnchorNode.getObject(value);
@@ -96,6 +99,7 @@
             cardBase = cardBase.add(Word.unsigned(cardTableStart()));
         }
         Word cardAddress = cardBase.add(displacement);
+
         if (xorResult.notEqual(Word.zero())) {
             if (writtenValue.notEqual(Word.zero())) {
                 byte cardByte = cardAddress.readByte(0);
@@ -115,14 +119,24 @@
     }
 
     @Snippet
-    public static void serialWriteBarrierPost(@Parameter("object") Object obj, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) {
+    public static void serialFieldWriteBarrier(@Parameter("object") Object obj) {
         Object object = FixedValueAnchorNode.getObject(obj);
-        Pointer oop;
-        if (usePrecise) {
-            oop = Word.fromArray(object, location);
+        Pointer oop = Word.fromObject(object);
+        Word base = (Word) oop.unsignedShiftRight(cardTableShift());
+        long startAddress = cardTableStart();
+        int displacement = 0;
+        if (((int) startAddress) == startAddress) {
+            displacement = (int) startAddress;
         } else {
-            oop = Word.fromObject(object);
+            base = base.add(Word.unsigned(cardTableStart()));
         }
+        base.writeByte(displacement, (byte) 0);
+    }
+
+    @Snippet
+    public static void serialArrayWriteBarrier(@Parameter("object") Object obj, @Parameter("location") Object location) {
+        Object object = FixedValueAnchorNode.getObject(obj);
+        Pointer oop = Word.fromArray(object, location);
         Word base = (Word) oop.unsignedShiftRight(cardTableShift());
         long startAddress = cardTableStart();
         int displacement = 0;
@@ -136,30 +150,40 @@
 
     public static class Templates extends AbstractTemplates<WriteBarrierSnippets> {
 
-        private final ResolvedJavaMethod serialWriteBarrierPost;
-        private final ResolvedJavaMethod g1WriteBarrierPre;
-        private final ResolvedJavaMethod g1WriteBarrierPost;
+        private final ResolvedJavaMethod serialFieldWriteBarrier;
+        private final ResolvedJavaMethod serialArrayWriteBarrier;
+        private final ResolvedJavaMethod g1PreWriteBarrier;
+        private final ResolvedJavaMethod g1PostWriteBarrier;
 
         public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) {
             super(runtime, assumptions, target, WriteBarrierSnippets.class);
-            serialWriteBarrierPost = snippet("serialWriteBarrierPost", Object.class, Object.class, boolean.class);
-            g1WriteBarrierPre = snippet("g1WriteBarrierPre", Object.class, Object.class, Object.class, boolean.class);
-            g1WriteBarrierPost = snippet("g1WriteBarrierPost", Object.class, Object.class, Object.class, boolean.class);
+            serialFieldWriteBarrier = snippet("serialFieldWriteBarrier", Object.class);
+            serialArrayWriteBarrier = snippet("serialArrayWriteBarrier", Object.class, Object.class);
+            g1PreWriteBarrier = snippet("g1PreWriteBarrier", Object.class, Object.class, Object.class, boolean.class);
+            g1PostWriteBarrier = snippet("g1PostWriteBarrier", Object.class, Object.class, Object.class, boolean.class);
         }
 
-        public void lower(SerialWriteBarrierPost fieldWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
-            ResolvedJavaMethod method = serialWriteBarrierPost;
+        public void lower(ArrayWriteBarrier arrayWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+            ResolvedJavaMethod method = serialArrayWriteBarrier;
             Key key = new Key(method);
-            key.add("usePrecise", fieldWriteBarrier.usePrecise());
+            Arguments arguments = new Arguments();
+            arguments.add("object", arrayWriteBarrier.getObject());
+            arguments.add("location", arrayWriteBarrier.getLocation());
+            SnippetTemplate template = cache.get(key, assumptions);
+            template.instantiate(runtime, arrayWriteBarrier, DEFAULT_REPLACER, arguments);
+        }
+
+        public void lower(FieldWriteBarrier fieldWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+            ResolvedJavaMethod method = serialFieldWriteBarrier;
+            Key key = new Key(method);
             Arguments arguments = new Arguments();
             arguments.add("object", fieldWriteBarrier.getObject());
-            arguments.add("location", fieldWriteBarrier.getLocation());
             SnippetTemplate template = cache.get(key, assumptions);
             template.instantiate(runtime, fieldWriteBarrier, DEFAULT_REPLACER, arguments);
         }
 
-        public void lower(G1WriteBarrierPre writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) {
-            ResolvedJavaMethod method = g1WriteBarrierPre;
+        public void lower(WriteBarrierPre writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) {
+            ResolvedJavaMethod method = g1PreWriteBarrier;
             Key key = new Key(method);
             key.add("doLoad", writeBarrierPre.doLoad());
             Arguments arguments = new Arguments();
@@ -170,8 +194,8 @@
             template.instantiate(runtime, writeBarrierPre, DEFAULT_REPLACER, arguments);
         }
 
-        public void lower(G1WriteBarrierPost writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) {
-            ResolvedJavaMethod method = g1WriteBarrierPost;
+        public void lower(WriteBarrierPost writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) {
+            ResolvedJavaMethod method = g1PostWriteBarrier;
             Key key = new Key(method);
             key.add("usePrecise", writeBarrierPost.usePrecise());
             Arguments arguments = new Arguments();
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Apr 03 14:41:22 2013 +0200
@@ -33,7 +33,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -235,21 +234,21 @@
             ValueNode value = localAt(i);
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value)));
+                storeLocal(i, ProxyNode.forValue(value, loopExit, graph));
             }
         }
         for (int i = 0; i < stackSize(); i++) {
             ValueNode value = stackAt(i);
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                storeStack(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value)));
+                storeStack(i, ProxyNode.forValue(value, loopExit, graph));
             }
         }
         for (int i = 0; i < locks.length; i++) {
             ValueNode value = locks[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = graph.unique(new ProxyNode(value, loopExit, PhiType.Value));
+                locks[i] = ProxyNode.forValue(value, loopExit, graph);
             }
         }
     }
@@ -259,21 +258,21 @@
             ValueNode value = localAt(i);
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, graph.unique(new ProxyNode(value, begin, PhiType.Value)));
+                storeLocal(i, ProxyNode.forValue(value, begin, graph));
             }
         }
         for (int i = 0; i < stackSize(); i++) {
             ValueNode value = stackAt(i);
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                storeStack(i, graph.unique(new ProxyNode(value, begin, PhiType.Value)));
+                storeStack(i, ProxyNode.forValue(value, begin, graph));
             }
         }
         for (int i = 0; i < locks.length; i++) {
             ValueNode value = locks[i];
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = graph.unique(new ProxyNode(value, begin, PhiType.Value));
+                locks[i] = ProxyNode.forValue(value, begin, graph);
             }
         }
     }
@@ -377,10 +376,10 @@
     }
 
     /**
-     * @return true if there are no locks within this frame state.
+     * @return the current lock depth
      */
-    public boolean locksEmpty() {
-        return locks.length == 0;
+    public int lockDepth() {
+        return locks.length;
     }
 
     /**
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -1153,18 +1153,18 @@
     }
 
     private MonitorEnterNode genMonitorEnter(ValueNode x) {
+        MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x, frameState.lockDepth()));
         frameState.pushLock(x);
-        MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x));
         appendWithBCI(monitorEnter);
         return monitorEnter;
     }
 
     private MonitorExitNode genMonitorExit(ValueNode x) {
         ValueNode lockedObject = frameState.popLock();
+        MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x, frameState.lockDepth()));
         if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) {
             throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject));
         }
-        MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x));
         appendWithBCI(monitorExit);
         return monitorExit;
     }
@@ -1568,7 +1568,7 @@
         }
 
         synchronizedEpilogue(FrameState.AFTER_BCI);
-        if (!frameState.locksEmpty()) {
+        if (frameState.lockDepth() != 0) {
             throw new BailoutException("unbalanced monitors");
         }
         ReturnNode returnNode = currentGraph.add(new ReturnNode(x));
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/ConvertJTT.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/ConvertJTT.java	Wed Apr 03 14:41:22 2013 +0200
@@ -52,8 +52,7 @@
                         try {
                             processFile(file.toPath(), new File(targetDir, file.getName()).toPath(), packageName);
                         } catch (RuntimeException e) {
-                            e.printStackTrace();
-                            System.out.println("in file " + file.getAbsolutePath());
+                            throw new RuntimeException(String.format("Exception while processing file %s", file.getAbsolutePath()), e);
                         }
                     }
                 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Wed Apr 03 14:41:22 2013 +0200
@@ -50,10 +50,8 @@
             FloatField = Field_get03.class.getField("floatField");
             DoubleField = Field_get03.class.getField("doubleField");
             BooleanField = Field_get03.class.getField("booleanField");
-        } catch (SecurityException e) {
-            e.printStackTrace();
-        } catch (NoSuchFieldException e) {
-            e.printStackTrace();
+        } catch (SecurityException | NoSuchFieldException e) {
+            throw new RuntimeException(e);
         }
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Wed Apr 03 14:41:22 2013 +0200
@@ -80,24 +80,23 @@
      * We filter out constant and illegal values ourself before calling the procedure, so
      * {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set.
      */
-    private static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
+    protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
 
-    private void processValues(Value[] values, ValueProcedure proc) {
+    protected void processValues(Value[] values, ValueProcedure proc) {
         for (int i = 0; i < values.length; i++) {
             Value value = values[i];
-            if (value instanceof MonitorValue) {
-                MonitorValue monitor = (MonitorValue) value;
-                if (processed(monitor.getOwner())) {
-                    monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
-                }
-
-            } else if (processed(value)) {
-                values[i] = proc.doValue(value, OperandMode.ALIVE, STATE_FLAGS);
-            }
+            values[i] = processValue(proc, value);
         }
     }
 
-    private boolean processed(Value value) {
+    protected Value processValue(ValueProcedure proc, Value value) {
+        if (processed(value)) {
+            return proc.doValue(value, OperandMode.ALIVE, STATE_FLAGS);
+        }
+        return value;
+    }
+
+    protected boolean processed(Value value) {
         if (isIllegal(value)) {
             // Ignore dead local variables.
             return false;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Apr 03 14:41:22 2013 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.VirtualState.VirtualClosure;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.type.*;
 
 public abstract class LoopFragment {
 
@@ -275,8 +274,7 @@
                 final ValueNode replaceWith;
                 ProxyNode newVpn = getDuplicatedNode(vpn);
                 if (newVpn != null) {
-                    PhiNode phi = graph.add(vpn.type() == PhiType.Value ? vpn.stamp() == StampFactory.virtual() ? new PhiNode(vpn.stamp(), merge) : new PhiNode(vpn.kind(), merge) : new PhiNode(
-                                    vpn.type(), merge));
+                    PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge, vpn.getIdentity()));
                     phi.addInput(vpn);
                     phi.addInput(newVpn);
                     replaceWith = phi;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Wed Apr 03 14:41:22 2013 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 public class LoopFragmentInside extends LoopFragment {
@@ -162,8 +161,7 @@
             }
             // create a new phi (we don't patch the old one since some usages of the old one may
             // still be valid)
-            PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? phi.stamp() == StampFactory.virtual() ? new PhiNode(phi.stamp(), loopBegin) : new PhiNode(phi.kind(), loopBegin) : new PhiNode(
-                            phi.type(), loopBegin));
+            PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin, phi.getIdentity()));
             newPhi.addInput(first);
             for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
                 newPhi.addInput(phi.valueAt(end));
@@ -253,8 +251,7 @@
             }
 
             for (final PhiNode phi : loopBegin.phis().snapshot()) {
-                final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? phi.stamp() == StampFactory.virtual() ? new PhiNode(phi.stamp(), newExitMerge) : new PhiNode(phi.kind(), newExitMerge)
-                                : new PhiNode(phi.type(), newExitMerge));
+                final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity()));
                 for (EndNode end : newExitMerge.forwardEnds()) {
                     LoopEndNode loopEnd = reverseEnds.get(end);
                     ValueNode prim = prim(phi.valueAt(loopEnd));
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -34,12 +34,17 @@
     private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls");
     private final GraalCodeCacheProvider runtime;
     private final Assumptions assumptions;
+    private int unrollCount;
 
     public LoopFullUnrollPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) {
         this.runtime = runtime;
         this.assumptions = assumptions;
     }
 
+    public int getUnrollCount() {
+        return unrollCount;
+    }
+
     @Override
     protected void run(StructuredGraph graph) {
         if (graph.hasLoops()) {
@@ -55,11 +60,11 @@
                         FULLY_UNROLLED_LOOPS.increment();
                         Debug.dump(graph, "After fullUnroll %s", loop);
                         peeled = true;
+                        unrollCount++;
                         break;
                     }
                 }
             } while (peeled);
         }
     }
-
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Apr 03 14:41:22 2013 +0200
@@ -273,6 +273,18 @@
     }
 
     /**
+     * Gets the number of locked monitors in this frame state and all
+     * {@linkplain #outerFrameState() outer} frame states.
+     */
+    public int nestedLockDepth() {
+        int depth = locksSize();
+        for (FrameState outer = outerFrameState(); outer != null; outer = outer.outerFrameState()) {
+            depth += outer.locksSize();
+        }
+        return depth;
+    }
+
+    /**
      * Gets the value in the local variables at the specified index.
      * 
      * @param i the index into the locals
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -50,6 +50,7 @@
     @Input(notDataflow = true) private MergeNode merge;
     @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
     private final PhiType type;
+    private final Object identity;
 
     /**
      * Create a value phi ({@link PhiType#Value}) with the specified kind.
@@ -66,6 +67,7 @@
         assert stamp != StampFactory.forVoid();
         this.type = PhiType.Value;
         this.merge = merge;
+        this.identity = null;
     }
 
     /**
@@ -74,11 +76,12 @@
      * @param type the type of the new phi
      * @param merge the merge that the new phi belongs to
      */
-    public PhiNode(PhiType type, MergeNode merge) {
+    public PhiNode(PhiType type, MergeNode merge, Object identity) {
         super(type.stamp);
         assert type.stamp != null : merge + " " + type;
         this.type = type;
         this.merge = merge;
+        this.identity = identity;
     }
 
     public PhiType type() {
@@ -89,6 +92,11 @@
         return merge;
     }
 
+    public Object getIdentity() {
+        assert type != PhiType.Value;
+        return identity;
+    }
+
     public void setMerge(MergeNode x) {
         updateUsages(merge, x);
         merge = x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -40,10 +40,12 @@
     @Input(notDataflow = true) private BeginNode proxyPoint;
     @Input private ValueNode value;
     private final PhiType type;
+    private final Object identity;
 
-    public ProxyNode(ValueNode value, BeginNode exit, PhiType type) {
+    public ProxyNode(ValueNode value, BeginNode exit, PhiType type, Object identity) {
         super(type == PhiType.Value ? value.stamp() : type.stamp);
         this.type = type;
+        this.identity = identity;
         assert exit != null;
         this.proxyPoint = exit;
         this.value = value;
@@ -71,6 +73,11 @@
         return type;
     }
 
+    public Object getIdentity() {
+        assert type != PhiType.Value;
+        return identity;
+    }
+
     @Override
     public boolean verify() {
         assert value != null;
@@ -100,4 +107,13 @@
             }
         }
     }
+
+    public static ProxyNode forValue(ValueNode value, BeginNode exit, StructuredGraph graph) {
+        return graph.unique(new ProxyNode(value, exit, PhiType.Value, null));
+    }
+
+    public static ProxyNode forMemory(ValueNode value, BeginNode exit, Object location, StructuredGraph graph) {
+        return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location));
+    }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -45,6 +45,20 @@
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new IntegerAddNode(kind(), y(), x()));
         }
+        if (x() instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) x();
+            if (sub.y() == y()) {
+                // (a - b) + b
+                return sub.x();
+            }
+        }
+        if (y() instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) y();
+            if (sub.y() == x()) {
+                // b + (a - b)
+                return sub.x();
+            }
+        }
         if (x().isConstant()) {
             if (kind() == Kind.Int) {
                 return ConstantNode.forInt(x().asConstant().asInt() + y().asConstant().asInt(), graph());
@@ -73,6 +87,8 @@
         }
         if (x() instanceof NegateNode) {
             return IntegerArithmeticNode.sub(y(), ((NegateNode) x()).x());
+        } else if (y() instanceof NegateNode) {
+            return IntegerArithmeticNode.sub(x(), ((NegateNode) y()).x());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -45,6 +45,40 @@
         if (x() == y()) {
             return ConstantNode.forIntegerKind(kind(), 0, graph());
         }
+        if (x() instanceof IntegerAddNode) {
+            IntegerAddNode x = (IntegerAddNode) x();
+            if (x.y() == y()) {
+                // (a + b) - b
+                return x.x();
+            }
+            if (x.x() == y()) {
+                // (a + b) - a
+                return x.y();
+            }
+        } else if (x() instanceof IntegerSubNode) {
+            IntegerSubNode x = (IntegerSubNode) x();
+            if (x.x() == y()) {
+                // (a - b) - a
+                return graph().unique(new NegateNode(x.y()));
+            }
+        }
+        if (y() instanceof IntegerAddNode) {
+            IntegerAddNode y = (IntegerAddNode) y();
+            if (y.x() == x()) {
+                // a - (a + b)
+                return graph().unique(new NegateNode(y.y()));
+            }
+            if (y.y() == x()) {
+                // b - (a + b)
+                return graph().unique(new NegateNode(y.x()));
+            }
+        } else if (y() instanceof IntegerSubNode) {
+            IntegerSubNode y = (IntegerSubNode) y();
+            if (y.x() == x()) {
+                // a - (a - b)
+                return y.y();
+            }
+        }
         if (x().isConstant() && y().isConstant()) {
             if (kind() == Kind.Int) {
                 return ConstantNode.forInt(x().asConstant().asInt() - y().asConstant().asInt(), graph());
@@ -76,6 +110,9 @@
             }
             return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
         }
+        if (y() instanceof NegateNode) {
+            return IntegerArithmeticNode.add(x(), ((NegateNode) y()).x());
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.debug;
 
+import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -45,28 +46,39 @@
     private static final int MAX_COUNTERS = 10 * 1024;
     private static final long[] COUNTERS = new long[MAX_COUNTERS];
     private static final HashMap<String, Integer> INDEXES = new HashMap<>();
+    public static String excludedClassPrefix = null;
+    public static boolean enabled = false;
+
     private final String name;
+    private final long increment;
     private final boolean addContext;
 
-    public DynamicCounterNode(String name, boolean addContext) {
+    public DynamicCounterNode(String name, long increment, boolean addContext) {
         super(StampFactory.forVoid());
+        if (!enabled) {
+            throw new GraalInternalError("dynamic counters not enabled");
+        }
         this.name = name;
+        this.increment = increment;
         this.addContext = addContext;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public long getIncrement() {
+        return increment;
+    }
+
+    public boolean isAddContext() {
+        return addContext;
+    }
+
     private static synchronized int getIndex(String name) {
         Integer index = INDEXES.get(name);
         if (index == null) {
             index = INDEXES.size();
-            if (index == 0) {
-                Runtime.getRuntime().addShutdownHook(new Thread() {
-
-                    @Override
-                    public void run() {
-                        dump();
-                    }
-                });
-            }
             INDEXES.put(name, index);
             if (index >= MAX_COUNTERS) {
                 throw new GraalInternalError("too many dynamic counters");
@@ -77,44 +89,59 @@
         }
     }
 
-    private static synchronized void dump() {
+    public static synchronized void dump(PrintStream out, double seconds) {
         TreeMap<Long, String> sorted = new TreeMap<>();
 
         long sum = 0;
         for (int i = 0; i < MAX_COUNTERS; i++) {
             sum += COUNTERS[i];
         }
+        long cutoff = sum / 1000;
         int cnt = 0;
         for (Map.Entry<String, Integer> entry : INDEXES.entrySet()) {
-            sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey());
+            if (COUNTERS[entry.getValue()] > cutoff) {
+                sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey());
+            }
         }
 
+        out.println("=========== dynamic counters, time = " + seconds + " s");
         for (Map.Entry<Long, String> entry : sorted.entrySet()) {
-            System.out.println((entry.getKey() / MAX_COUNTERS) + ": " + entry.getValue());
+            long counter = entry.getKey() / MAX_COUNTERS;
+            out.println((int) (counter / seconds) + "/s \t" + (counter * 100 / sum) + "% \t" + entry.getValue());
         }
-        System.out.println(sum + ": total");
+        out.println((int) (sum / seconds) + "/s: total");
+        out.println("============================");
 
+        clear();
+    }
+
+    public static void clear() {
+        Arrays.fill(COUNTERS, 0);
     }
 
     @Override
     public void lower(LoweringTool tool) {
-        int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name);
+        StructuredGraph graph = (StructuredGraph) graph();
+        if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
+            int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name);
 
-        StructuredGraph graph = (StructuredGraph) graph();
-        ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph);
-        ConstantNode indexConstant = ConstantNode.forInt(index, graph);
-        LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
-        IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(1, graph)));
-        StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
+            ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph);
+            ConstantNode indexConstant = ConstantNode.forInt(index, graph);
+            LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
+            IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph)));
+            StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
 
-        graph.addBeforeFixed(this, load);
-        graph.addBeforeFixed(this, store);
+            graph.addBeforeFixed(this, load);
+            graph.addBeforeFixed(this, store);
+        }
         graph.removeFixed(this);
     }
 
-    public static void createCounter(String name, FixedNode before, boolean addContext) {
-        StructuredGraph graph = (StructuredGraph) before.graph();
-        DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, addContext));
-        graph.addBeforeFixed(before, counter);
+    public static void addCounterBefore(String name, long increment, boolean addContext, FixedNode position) {
+        if (enabled) {
+            StructuredGraph graph = (StructuredGraph) position.graph();
+            DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, increment, addContext));
+            graph.addBeforeFixed(position, counter);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.debug;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This is a special version of the dynamic counter node that removes itself as soon as it's the
+ * only usage of the associated node. This way it only increments the counter if the node is
+ * actually executed.
+ */
+public class SurvivingCounterNode extends DynamicCounterNode implements Simplifiable, Virtualizable {
+
+    @Input private ValueNode checkedValue;
+
+    public SurvivingCounterNode(String name, long increment, boolean addContext, ValueNode checkedValue) {
+        super(name, increment, addContext);
+        this.checkedValue = checkedValue;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (checkedValue instanceof FloatingNode && checkedValue.usages().count() == 1) {
+            tool.addToWorkList(checkedValue);
+            ((StructuredGraph) graph()).removeFixed(this);
+            // ((StructuredGraph) graph()).replaceFixedWithFixed(this, graph().add(new
+            // DynamicCounterNode("non-surviving " + getName(), getIncrement(), isAddContext())));
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(checkedValue);
+        if (state != null && state.getState() == EscapeState.Virtual) {
+            tool.delete();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,39 @@
+/*
+ * 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.extended;
+
+/**
+ * Denotes an instruction that references a monitor and wants to know its lock nesting depth.
+ */
+public interface MonitorReference {
+
+    /**
+     * Sets the depth of the lock referenced by this operation.
+     */
+    void setLockDepth(int lockDepth);
+
+    /**
+     * Gets the depth of the lock referenced by this operation.
+     */
+    int getLockDepth();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * 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.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * An analog to {@link AccessNode} with the additional semantics of null-checking the receiver
- * object before the access.
- */
-public abstract class SafeAccessNode extends FixedWithNextNode {
-
-    @Input private ValueNode object;
-    @Input private LocationNode location;
-
-    public SafeAccessNode(ValueNode object, LocationNode location, Stamp stamp) {
-        super(stamp);
-        this.object = object;
-        this.location = location;
-    }
-
-    public ValueNode object() {
-        return object;
-    }
-
-    public LocationNode location() {
-        return location;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * 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.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * An analog to {@link ReadNode} with the additional semantics of null-checking the receiver object
- * before reading from it.
- */
-public class SafeReadNode extends SafeAccessNode implements Lowerable {
-
-    public SafeReadNode(ValueNode object, LocationNode location, Stamp stamp) {
-        super(object, location, stamp);
-        assert object != null && location != null;
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        ValueNode guard = tool.createNullCheckGuard(object());
-        ReadNode read = graph.add(new ReadNode(object(), location(), stamp()));
-        read.dependencies().add(guard);
-
-        graph.replaceFixedWithFixed(this, read);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * 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.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * An analog to {@link WriteNode} with the additional semantics of null-checking the receiver object
- * before writing to it.
- */
-public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable {
-
-    @Input private ValueNode value;
-    @Input(notDataflow = true) private FrameState stateAfter;
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
-        return true;
-    }
-
-    public SafeWriteNode(ValueNode object, ValueNode value, LocationNode location) {
-        super(object, location, StampFactory.forVoid());
-        this.value = value;
-    }
-
-    public ValueNode value() {
-        return value;
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        ValueNode guard = tool.createNullCheckGuard(object());
-        WriteNode write = graph.add(new WriteNode(object(), value(), location()));
-        write.dependencies().add(guard);
-        graph.replaceFixedWithFixed(this, write);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -29,15 +29,18 @@
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter {
+public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter, MonitorReference {
+
+    private int lockDepth;
 
     /**
      * Creates a new MonitorEnterNode.
      * 
      * @param object the instruction producing the object
      */
-    public MonitorEnterNode(ValueNode object) {
+    public MonitorEnterNode(ValueNode object, int lockDepth) {
         super(object);
+        this.lockDepth = lockDepth;
     }
 
     @Override
@@ -48,4 +51,12 @@
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -30,15 +30,18 @@
 /**
  * The {@code MonitorEnterNode} represents a monitor release.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit {
+public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference {
+
+    private int lockDepth;
 
     /**
      * Creates a new MonitorExitNode.
      * 
      * @param object the instruction produces the object value
      */
-    public MonitorExitNode(ValueNode object) {
+    public MonitorExitNode(ValueNode object, int lockDepth) {
         super(object);
+        this.lockDepth = lockDepth;
     }
 
     @Override
@@ -49,4 +52,12 @@
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -139,7 +139,7 @@
         }
         Graph graph = merge.graph();
         for (GuardNode guard : hits) {
-            PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge));
+            PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge, null));
             for (EndNode otherEnd : merge.forwardEnds()) {
                 phi.addInput(graph.unique(new GuardNode(guard.condition(), BeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated())));
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -186,7 +186,7 @@
                         } else if (merged == null) {
                             merged = last;
                         } else {
-                            PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
+                            PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge, key));
                             for (int j = 0; j < mergedStatesCount; j++) {
                                 phi.addInput(merged);
                             }
@@ -232,7 +232,7 @@
 
             Map<Object, PhiNode> phis = new HashMap<>();
             for (Object location : modifiedLocations) {
-                PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop));
+                PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop, location));
                 phi.addInput(initialState.getLastLocationAccess(location));
                 phis.put(location, phi);
                 initialState.lastMemorySnapshot.put(location, phi);
@@ -254,7 +254,7 @@
                 for (Object location : modifiedLocations) {
                     ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
                     if (lastAccessAtExit != null) {
-                        state.lastMemorySnapshot.put(location, loop.graph().add(new ProxyNode(lastAccessAtExit, exit, PhiType.Memory)));
+                        state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, (StructuredGraph) loop.graph()));
                     }
                 }
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -57,20 +57,20 @@
     private final OptimisticOptimizations optimisticOpts;
     private CustomCanonicalizer customCanonicalizer;
 
+    private int inliningCount;
+
+    private int maxMethodPerInlining = Integer.MAX_VALUE;
+
     // Metrics
     private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
     private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
     private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
     private static final DebugMetric metricInliningRuns = Debug.metric("Runs");
 
-    public InliningPhase(MetaAccessProvider runtime, Collection<Invoke> hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
+    public InliningPhase(MetaAccessProvider runtime, Map<Invoke, Double> hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
         this(runtime, assumptions, cache, plan, createInliningPolicy(runtime, assumptions, optimisticOpts, hints), optimisticOpts);
     }
 
-    public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) {
-        this.customCanonicalizer = customCanonicalizer;
-    }
-
     public InliningPhase(MetaAccessProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) {
         this.runtime = runtime;
         this.assumptions = assumptions;
@@ -79,6 +79,18 @@
         this.inliningPolicy = inliningPolicy;
         this.optimisticOpts = optimisticOpts;
     }
+    
+    public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) {
+        this.customCanonicalizer = customCanonicalizer;
+    }
+    
+    public void setMaxMethodsPerInlining(int max) {
+        maxMethodPerInlining = max;
+    }
+    
+    public int getInliningCount() {
+        return inliningCount;
+    }
 
     @Override
     protected void run(final StructuredGraph graph) {
@@ -89,6 +101,7 @@
 
             if (candidate != null) {
                 boolean isWorthInlining = inliningPolicy.isWorthInlining(candidate);
+                isWorthInlining &= candidate.numberOfMethods() <= maxMethodPerInlining;
 
                 metricInliningConsidered.increment();
                 if (isWorthInlining) {
@@ -102,6 +115,7 @@
                         if (GraalOptions.OptCanonicalizer) {
                             new CanonicalizerPhase(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph);
                         }
+                        inliningCount++;
                         metricInliningPerformed.increment();
                     } catch (BailoutException bailout) {
                         throw bailout;
@@ -164,9 +178,9 @@
     private static class GreedySizeBasedInliningDecision implements InliningDecision {
 
         private final MetaAccessProvider runtime;
-        private final Collection<Invoke> hints;
+        private final Map<Invoke, Double> hints;
 
-        public GreedySizeBasedInliningDecision(MetaAccessProvider runtime, Collection<Invoke> hints) {
+        public GreedySizeBasedInliningDecision(MetaAccessProvider runtime, Map<Invoke, Double> hints) {
             this.runtime = runtime;
             this.hints = hints;
         }
@@ -185,9 +199,14 @@
                 return InliningUtil.logInlinedMethod(info, "intrinsic");
             }
 
-            int bytecodeSize = bytecodeCodeSize(info);
-            int complexity = compilationComplexity(info);
-            int compiledCodeSize = compiledCodeSize(info);
+            double bonus = 1;
+            if (hints != null && hints.containsKey(info.invoke())) {
+                bonus = hints.get(info.invoke());
+            }
+
+            int bytecodeSize = (int) (bytecodeCodeSize(info) / bonus);
+            int complexity = (int) (compilationComplexity(info) / bonus);
+            int compiledCodeSize = (int) (compiledCodeSize(info) / bonus);
             double relevance = info.invoke().inliningRelevance();
 
             /*
@@ -213,13 +232,12 @@
             int invokeUsages = countInvokeUsages(info);
             int moreSpecificArguments = countMoreSpecificArgumentInfo(info);
             int level = info.level();
-            boolean preferredInvoke = hints != null && hints.contains(info.invoke());
 
             // TODO (chaeubl): compute metric that is used to check if this method should be inlined
 
             return InliningUtil.logNotInlinedMethod(info,
-                            "(relevance=%f, bytecodes=%d, complexity=%d, codeSize=%d, probability=%f, transferredValues=%d, invokeUsages=%d, moreSpecificArguments=%d, level=%d, preferred=%b)",
-                            relevance, bytecodeSize, complexity, compiledCodeSize, probability, transferredValues, invokeUsages, moreSpecificArguments, level, preferredInvoke);
+                            "(relevance=%f, bytecodes=%d, complexity=%d, codeSize=%d, probability=%f, transferredValues=%d, invokeUsages=%d, moreSpecificArguments=%d, level=%d, bonus=%f)", relevance,
+                            bytecodeSize, complexity, compiledCodeSize, probability, transferredValues, invokeUsages, moreSpecificArguments, level, bonus);
         }
 
         private static boolean isTrivialInlining(int bytecodeSize, int complexity, int compiledCodeSize) {
@@ -329,16 +347,14 @@
     private static class CFInliningPolicy implements InliningPolicy {
 
         private final InliningDecision inliningDecision;
-        private final Collection<Invoke> hints;
         private final Assumptions assumptions;
         private final OptimisticOptimizations optimisticOpts;
         private final Deque<Invoke> sortedInvokes;
         private NodeBitMap visitedFixedNodes;
         private FixedNode invokePredecessor;
 
-        public CFInliningPolicy(InliningDecision inliningPolicy, Collection<Invoke> hints, Assumptions assumptions, OptimisticOptimizations optimisticOpts) {
+        public CFInliningPolicy(InliningDecision inliningPolicy, Assumptions assumptions, OptimisticOptimizations optimisticOpts) {
             this.inliningDecision = inliningPolicy;
-            this.hints = hints;
             this.assumptions = assumptions;
             this.optimisticOpts = optimisticOpts;
             this.sortedInvokes = new ArrayDeque<>();
@@ -371,9 +387,6 @@
         public void initialize(StructuredGraph graph) {
             visitedFixedNodes = graph.createNodeBitMap(true);
             scanGraphForInvokes(graph.start());
-            if (hints != null) {
-                sortedInvokes.retainAll(hints);
-            }
         }
 
         public void scanInvokes(Iterable<? extends Node> newNodes) {
@@ -500,8 +513,8 @@
         }
     }
 
-    private static InliningPolicy createInliningPolicy(MetaAccessProvider runtime, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Collection<Invoke> hints) {
+    private static InliningPolicy createInliningPolicy(MetaAccessProvider runtime, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Map<Invoke, Double> hints) {
         InliningDecision inliningDecision = new GreedySizeBasedInliningDecision(runtime, hints);
-        return new CFInliningPolicy(inliningDecision, hints, assumptions, optimisticOpts);
+        return new CFInliningPolicy(inliningDecision, assumptions, optimisticOpts);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Apr 03 14:41:22 2013 +0200
@@ -1094,6 +1094,7 @@
 
         FrameState outerFrameState = null;
         double invokeProbability = invoke.node().probability();
+        int callerLockDepth = stateAfter.nestedLockDepth();
         for (Node node : duplicates.values()) {
             if (GraalOptions.ProbabilityAnalysis) {
                 if (node instanceof FixedNode) {
@@ -1137,6 +1138,10 @@
                     }
                 }
             }
+            if (callerLockDepth != 0 && node instanceof MonitorReference) {
+                MonitorReference monitor = (MonitorReference) node;
+                monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
+            }
         }
 
         Node returnValue = null;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
 
@@ -86,7 +85,7 @@
         if (lastLocationAccess instanceof ProxyNode) {
             ProxyNode proxy = (ProxyNode) lastLocationAccess;
             ValueNode value = getValue(n, proxy.value(), nodeMap);
-            return lastLocationAccess.graph().add(new ProxyNode(value, proxy.proxyPoint(), PhiType.Value));
+            return ProxyNode.forValue(value, proxy.proxyPoint(), (StructuredGraph) lastLocationAccess.graph());
         }
         if (lastLocationAccess instanceof WriteNode) {
             return ((WriteNode) lastLocationAccess).value();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -128,13 +128,21 @@
         }
     };
 
+    private int tailDuplicationCount;
+
+    public int getTailDuplicationCount() {
+        return tailDuplicationCount;
+    }
+
     @Override
     protected void run(StructuredGraph graph) {
         // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
         // duplication.
         for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
             if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) {
-                tailDuplicate(merge, DEFAULT_DECISION, null);
+                if (tailDuplicate(merge, DEFAULT_DECISION, null)) {
+                    tailDuplicationCount++;
+                }
             }
         }
     }
@@ -155,7 +163,7 @@
      *            {@link PiNode}, and is used to replace {@link PiNode#object()} with the
      *            {@link PiNode} in the duplicated branch that corresponds to the entry.
      */
-    public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) {
+    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) {
         assert !(merge instanceof LoopBeginNode);
         assert replacements == null || replacements.size() == merge.forwardEndCount();
         FixedNode fixed = merge;
@@ -179,15 +187,18 @@
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationEndPerformed.increment();
                     new DuplicationOperation(merge, replacements).duplicate();
+                    return true;
                 }
             } else if (merge.stateAfter() != null) {
                 metricDuplicationOther.increment();
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationOtherPerformed.increment();
                     new DuplicationOperation(merge, replacements).duplicate();
+                    return true;
                 }
             }
         }
+        return false;
     }
 
     /**
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Apr 03 14:41:22 2013 +0200
@@ -49,6 +49,7 @@
     public static boolean LimitInlinedRelevance              = true;
     public static float   BoostInliningForEscapeAnalysis     = 2f;
     public static float   RelevanceCapForInlining            = 1f;
+    public static boolean IterativeInlining                  = ____;
 
     public static int     TrivialBytecodeSize                = 10;
     public static int     NormalBytecodeSize                 = 150;
@@ -67,6 +68,8 @@
     public static int     EscapeAnalysisIterations           = 2;
     public static String  EscapeAnalyzeOnly                  = null;
     public static int     MaximumEscapeAnalysisArrayLength   = 32;
+    public static boolean PEAReadCache                       = ____;
+    public static boolean PEAInliningHints                   = ____;
 
     public static double  TailDuplicationProbability         = 0.5;
     public static int     TailDuplicationTrivialSize         = 1;
@@ -124,6 +127,8 @@
     public static String  LogFile                            = null;
     public static String  MethodFilter                       = null;
     public static boolean DumpOnError                        = ____;
+    public static boolean GenericDynamicCounters             = ____;
+    public static boolean BenchmarkDynamicCounters           = ____;
 
     // Ideal graph visualizer output settings
     public static boolean PrintBinaryGraphs                  = true;
@@ -209,7 +214,7 @@
     public static boolean IntrinsifyUnsafeMethods            = true;
     public static boolean IntrinsifyMathMethods              = true;
     public static boolean IntrinsifyAESMethods               = true;
-
+    public static boolean IntrinsifyInstalledCodeMethods     = true;
     /**
      * Counts the various paths taken through snippets.
      */
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Wed Apr 03 14:41:22 2013 +0200
@@ -41,7 +41,7 @@
 
         protected abstract StateT merge(MergeNode merge, List<StateT> states);
 
-        protected abstract StateT afterSplit(FixedNode node, StateT oldState);
+        protected abstract StateT cloneState(StateT oldState);
 
         protected abstract List<StateT> processLoop(Loop loop, StateT initialState);
     }
@@ -56,25 +56,31 @@
         LoopInfo<StateT> info = new LoopInfo<>();
         List<Block> predecessors = loop.header.getPredecessors();
         for (int i = 1; i < predecessors.size(); i++) {
-            info.endStates.add(blockEndStates.get(predecessors.get(i).getEndNode()));
+            StateT endState = blockEndStates.get(predecessors.get(i).getEndNode());
+            // make sure all end states are unique objects
+            info.endStates.add(closure.cloneState(endState));
         }
         for (Block loopExit : loop.exits) {
             assert loopExit.getPredecessorCount() == 1;
-            StateT exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode());
+            StateT exitState = blockEndStates.get(loopExit.getBeginNode());
             assert exitState != null;
-            info.exitStates.add(exitState);
+            // make sure all exit states are unique objects
+            info.exitStates.add(closure.cloneState(exitState));
         }
         return info;
     }
 
     public static <StateT> IdentityHashMap<FixedNode, StateT> apply(BlockIteratorClosure<StateT> closure, Block start, StateT initialState, Set<Block> boundary) {
         Deque<Block> blockQueue = new ArrayDeque<>();
-        IdentityHashMap<FixedNode, StateT> blockEndStates = new IdentityHashMap<>();
+        /*
+         * States are stored on EndNodes before merges, and on BeginNodes after ControlSplitNodes.
+         */
+        IdentityHashMap<FixedNode, StateT> states = new IdentityHashMap<>();
 
         StateT state = initialState;
         Block current = start;
 
-        do {
+        while (true) {
             if (boundary == null || boundary.contains(current)) {
                 closure.processBlock(current, state);
 
@@ -86,7 +92,7 @@
                         if (current.isLoopEnd()) {
                             // nothing to do... loop ends only lead to loop begins we've already
                             // visited
-                            blockEndStates.put(current.getEndNode(), state);
+                            states.put(current.getEndNode(), state);
                         } else {
                             // recurse into the loop
                             Loop loop = successor.getLoop();
@@ -98,14 +104,14 @@
                             int i = 0;
                             assert loop.exits.size() == exitStates.size();
                             for (Block exit : loop.exits) {
-                                blockEndStates.put(exit.getFirstPredecessor().getEndNode(), exitStates.get(i++));
+                                states.put(exit.getBeginNode(), exitStates.get(i++));
                                 blockQueue.addFirst(exit);
                             }
                         }
                     } else {
                         if (successor.getBeginNode() instanceof LoopExitNode) {
                             assert successor.getPredecessors().size() == 1;
-                            blockEndStates.put(current.getEndNode(), state);
+                            states.put(successor.getBeginNode(), state);
                             current = successor;
                             continue;
                         } else {
@@ -114,12 +120,12 @@
                                 EndNode end = (EndNode) current.getEndNode();
 
                                 // add the end node and see if the merge is ready for processing
-                                assert !blockEndStates.containsKey(end);
-                                blockEndStates.put(end, state);
+                                assert !states.containsKey(end);
+                                states.put(end, state);
                                 MergeNode merge = end.merge();
                                 boolean endsVisited = true;
                                 for (EndNode forwardEnd : merge.forwardEnds()) {
-                                    if (!blockEndStates.containsKey(forwardEnd)) {
+                                    if (!states.containsKey(forwardEnd)) {
                                         endsVisited = false;
                                         break;
                                     }
@@ -136,46 +142,34 @@
                     }
                 } else {
                     assert current.getSuccessors().size() > 1;
-                    blockEndStates.put(current.getEndNode(), state);
-                    for (Block block : current.getSuccessors()) {
-                        blockQueue.addFirst(block);
+                    for (int i = 0; i < current.getSuccessors().size(); i++) {
+                        Block successor = current.getSuccessors().get(i);
+                        blockQueue.addFirst(successor);
+                        states.put(successor.getBeginNode(), i == 0 ? state : closure.cloneState(state));
                     }
                 }
             }
 
             // get next queued block
             if (blockQueue.isEmpty()) {
-                current = null;
+                return states;
             } else {
-                int maxIterations = blockQueue.size();
-                while (maxIterations-- > 0) {
-                    current = blockQueue.removeFirst();
-                    if (current.getPredecessors().size() > 1) {
-                        MergeNode merge = (MergeNode) current.getBeginNode();
-                        ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
-                        for (int i = 0; i < merge.forwardEndCount(); i++) {
-                            StateT other = blockEndStates.get(merge.forwardEndAt(i));
-                            assert other != null;
-                            states.add(other);
-                        }
-                        state = closure.merge(merge, states);
-                        if (state != null) {
-                            break;
-                        } else {
-                            blockQueue.addLast(current);
-                            current = null;
-                        }
-                    } else {
-                        assert current.getPredecessors().size() == 1;
-                        assert current.getBeginNode().predecessor() != null;
-                        if (boundary == null || boundary.contains(current)) {
-                            state = closure.afterSplit(current.getBeginNode(), blockEndStates.get(current.getBeginNode().predecessor()));
-                            break;
-                        }
+                current = blockQueue.removeFirst();
+                if (current.getPredecessors().size() == 1) {
+                    state = states.get(current.getBeginNode());
+                } else {
+                    assert current.getPredecessors().size() > 1;
+                    MergeNode merge = (MergeNode) current.getBeginNode();
+                    ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
+                    for (int i = 0; i < merge.forwardEndCount(); i++) {
+                        StateT other = states.get(merge.forwardEndAt(i));
+                        assert other != null;
+                        mergedStates.add(other);
                     }
+                    state = closure.merge(merge, mergedStates);
                 }
+                assert state != null;
             }
-        } while (current != null);
-        return blockEndStates;
+        }
     }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -100,7 +100,7 @@
         }
 
         @Override
-        protected HashSet<FloatingReadNode> afterSplit(FixedNode node, HashSet<FloatingReadNode> oldState) {
+        protected HashSet<FloatingReadNode> cloneState(HashSet<FloatingReadNode> oldState) {
             return new HashSet<>(oldState);
         }
 
@@ -580,41 +580,45 @@
     }
 
     private void addToEarliestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
-        if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) {
-            return;
-        }
+        ScheduledNode instruction = i;
+        while (true) {
+            if (instruction == null || visited.isMarked(instruction) || cfg.getNodeToBlock().get(instruction) != b || instruction instanceof PhiNode || instruction instanceof LocalNode) {
+                return;
+            }
 
-        visited.mark(i);
-        for (Node usage : i.usages()) {
-            if (usage instanceof VirtualState) {
-                // only fixed nodes can have VirtualState -> no need to schedule them
-            } else {
-                if (i instanceof LoopExitNode && usage instanceof ProxyNode) {
-                    // value proxies should be scheduled before the loopexit, not after
+            visited.mark(instruction);
+            for (Node usage : instruction.usages()) {
+                if (usage instanceof VirtualState) {
+                    // only fixed nodes can have VirtualState -> no need to schedule them
                 } else {
-                    addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited);
-                }
-            }
-        }
-
-        if (i instanceof BeginNode) {
-            ArrayList<ProxyNode> proxies = (i instanceof LoopExitNode) ? new ArrayList<ProxyNode>() : null;
-            for (ScheduledNode inBlock : blockToNodesMap.get(b)) {
-                if (!visited.isMarked(inBlock)) {
-                    if (inBlock instanceof ProxyNode) {
-                        proxies.add((ProxyNode) inBlock);
+                    if (instruction instanceof LoopExitNode && usage instanceof ProxyNode) {
+                        // value proxies should be scheduled before the loopexit, not after
                     } else {
-                        addToEarliestSorting(b, inBlock, sortedInstructions, visited);
+                        addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited);
                     }
                 }
             }
-            sortedInstructions.add(i);
-            if (proxies != null) {
-                sortedInstructions.addAll(proxies);
+
+            if (instruction instanceof BeginNode) {
+                ArrayList<ProxyNode> proxies = (instruction instanceof LoopExitNode) ? new ArrayList<ProxyNode>() : null;
+                for (ScheduledNode inBlock : blockToNodesMap.get(b)) {
+                    if (!visited.isMarked(inBlock)) {
+                        if (inBlock instanceof ProxyNode) {
+                            proxies.add((ProxyNode) inBlock);
+                        } else {
+                            addToEarliestSorting(b, inBlock, sortedInstructions, visited);
+                        }
+                    }
+                }
+                sortedInstructions.add(instruction);
+                if (proxies != null) {
+                    sortedInstructions.addAll(proxies);
+                }
+                break;
+            } else {
+                sortedInstructions.add(instruction);
+                instruction = (ScheduledNode) instruction.predecessor();
             }
-        } else {
-            sortedInstructions.add(i);
-            addToEarliestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited);
         }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -62,11 +62,16 @@
         }
     }
 
-    public static Class<?>[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) {
-        int count = signature.getParameterCount(false);
+    public static Class<?>[] signatureToTypes(Signature signature, JavaType receiverType, ResolvedJavaType accessingClass) {
+        int count = signature.getParameterCount(receiverType != null);
         Class<?>[] result = new Class<?>[count];
-        for (int i = 0; i < result.length; ++i) {
-            result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader());
+        int j = 0;
+        if (receiverType != null) {
+            result[0] = getMirrorOrFail(receiverType.resolve(accessingClass), Thread.currentThread().getContextClassLoader());
+            j = 1;
+        }
+        for (int i = 0; i + j < result.length; ++i) {
+            result[i + j] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader());
         }
         return result;
     }
@@ -75,10 +80,12 @@
         ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod();
         NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
         ResolvedJavaType declaringClass = target.getDeclaringClass();
+        JavaType receiverType = invoke.methodCallTarget().isStatic() ? null : declaringClass;
         if (intrinsic != null) {
             assert target.getAnnotation(Fold.class) == null;
 
-            Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass);
+            // TODO mjj non-static intrinsic?
+            Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), null, declaringClass);
             ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass);
 
             // Prepare the arguments for the reflective constructor call on the node class.
@@ -98,7 +105,7 @@
             // Clean up checkcast instructions inserted by javac if the return type is generic.
             cleanUpReturnCheckCast(newInstance);
         } else if (target.getAnnotation(Fold.class) != null) {
-            Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass);
+            Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), receiverType, declaringClass);
 
             // Prepare the arguments for the reflective method call
             Object[] arguments = prepareArguments(invoke, parameterTypes, target, true);
@@ -109,6 +116,7 @@
             if (!invoke.methodCallTarget().isStatic()) {
                 receiver = arguments[0];
                 arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray();
+                parameterTypes = Arrays.asList(parameterTypes).subList(1, parameterTypes.length).toArray(new Class<?>[parameterTypes.length - 1]);
             }
 
             // Call the method
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Apr 03 14:41:22 2013 +0200
@@ -41,6 +41,7 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.Parameter;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.phases.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Apr 03 14:41:22 2013 +0200
@@ -56,6 +56,10 @@
         return targetMethod;
     }
 
+    public JavaType getReturnType() {
+        return returnType;
+    }
+
     @SuppressWarnings("unused")
     protected StructuredGraph getSnippetGraph(LoweringTool tool) {
         return null;
@@ -85,4 +89,19 @@
         invoke.setStateAfter(stateAfter());
         return invoke;
     }
+
+    protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
+        for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) {
+            if (invoke.methodCallTarget().targetMethod() != getTargetMethod()) {
+                throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName());
+            }
+            if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) {
+                InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), getBci()));
+                newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI)));
+                snippetGraph.replaceFixedWithFixed(invoke, newInvoke);
+            } else {
+                assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke;
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Wed Apr 03 14:41:22 2013 +0200
@@ -30,28 +30,104 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.virtual.nodes.*;
 
 class BlockState {
 
-    private final HashMap<VirtualObjectNode, ObjectState> objectStates = new HashMap<>();
-    private final HashMap<ValueNode, VirtualObjectNode> objectAliases = new HashMap<>();
-    private final HashMap<ValueNode, ValueNode> scalarAliases = new HashMap<>();
+    private final IdentityHashMap<VirtualObjectNode, ObjectState> objectStates = new IdentityHashMap<>();
+    private final IdentityHashMap<ValueNode, VirtualObjectNode> objectAliases;
+    private final IdentityHashMap<ValueNode, ValueNode> scalarAliases;
+    private final HashMap<ReadCacheEntry, ValueNode> readCache;
+
+    static class ReadCacheEntry {
+
+        public final Object identity;
+        public final ValueNode object;
+
+        public ReadCacheEntry(Object identity, ValueNode object) {
+            this.identity = identity;
+            this.object = object;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 31 + ((identity == null) ? 0 : identity.hashCode());
+            return 31 * result + ((object == null) ? 0 : object.hashCode());
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            ReadCacheEntry other = (ReadCacheEntry) obj;
+            return identity == other.identity && object == other.object;
+        }
+
+        @Override
+        public String toString() {
+            return object + ":" + identity;
+        }
+    }
 
     public BlockState() {
+        objectAliases = new IdentityHashMap<>();
+        scalarAliases = new IdentityHashMap<>();
+        readCache = new HashMap<>();
     }
 
     public BlockState(BlockState other) {
         for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) {
             objectStates.put(entry.getKey(), entry.getValue().cloneState());
         }
-        for (Map.Entry<ValueNode, VirtualObjectNode> entry : other.objectAliases.entrySet()) {
-            objectAliases.put(entry.getKey(), entry.getValue());
+        objectAliases = new IdentityHashMap<>(other.objectAliases);
+        scalarAliases = new IdentityHashMap<>(other.scalarAliases);
+        readCache = new HashMap<>(other.readCache);
+    }
+
+    public void addReadCache(ValueNode object, Object identity, ValueNode value) {
+        ValueNode cacheObject;
+        ObjectState obj = getObjectState(object);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheObject = obj.getMaterializedValue();
+        } else {
+            cacheObject = object;
         }
-        for (Map.Entry<ValueNode, ValueNode> entry : other.scalarAliases.entrySet()) {
-            scalarAliases.put(entry.getKey(), entry.getValue());
+        readCache.put(new ReadCacheEntry(identity, cacheObject), value);
+    }
+
+    public ValueNode getReadCache(ValueNode object, Object identity) {
+        ValueNode cacheObject;
+        ObjectState obj = getObjectState(object);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheObject = obj.getMaterializedValue();
+        } else {
+            cacheObject = object;
+        }
+        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject));
+        obj = getObjectState(cacheValue);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheValue = obj.getMaterializedValue();
+        } else {
+            cacheValue = getScalarAlias(cacheValue);
+        }
+        return cacheValue;
+    }
+
+    public void killReadCache(Object identity) {
+        if (identity == LocationNode.ANY_LOCATION) {
+            readCache.clear();
+        } else {
+            Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
+            while (iter.hasNext()) {
+                Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
+                if (entry.getKey().identity == identity) {
+                    iter.remove();
+                }
+            }
         }
     }
 
@@ -126,6 +202,13 @@
         }
         deferred.remove(virtual);
 
+        if (virtual instanceof VirtualInstanceNode) {
+            VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+            for (int i = 0; i < fieldState.length; i++) {
+                readCache.put(new ReadCacheEntry(instance.field(i), materialize), fieldState[i]);
+            }
+        }
+
         materializeEffects.addMaterialization(materialize, fixed, values);
     }
 
@@ -175,6 +258,63 @@
         return objectStates.toString();
     }
 
+    public void mergeReadCache(List<BlockState> states, MergeNode merge, GraphEffectList effects) {
+        for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+            ReadCacheEntry key = entry.getKey();
+            ValueNode value = entry.getValue();
+            boolean phi = false;
+            for (int i = 1; i < states.size(); i++) {
+                ValueNode otherValue = states.get(i).readCache.get(key);
+                if (otherValue == null) {
+                    value = null;
+                    phi = false;
+                    break;
+                }
+                if (!phi && otherValue != value) {
+                    phi = true;
+                }
+            }
+            if (phi) {
+                PhiNode phiNode = new PhiNode(value.kind(), merge);
+                effects.addFloatingNode(phiNode);
+                for (int i = 0; i < states.size(); i++) {
+                    effects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity));
+                }
+                readCache.put(key, phiNode);
+            } else if (value != null) {
+                readCache.put(key, value);
+            }
+        }
+        for (PhiNode phi : merge.phis()) {
+            if (phi.kind() == Kind.Object) {
+                for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                    if (entry.getKey().object == phi.valueAt(0)) {
+                        mergeReadCachePhi(phi, entry.getKey().identity, states, merge, effects);
+                    }
+                }
+
+            }
+        }
+    }
+
+    private void mergeReadCachePhi(PhiNode phi, Object identity, List<BlockState> states, MergeNode merge, GraphEffectList effects) {
+        ValueNode[] values = new ValueNode[phi.valueCount()];
+        for (int i = 0; i < phi.valueCount(); i++) {
+            ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity);
+            if (value == null) {
+                return;
+            }
+            values[i] = value;
+        }
+
+        PhiNode phiNode = new PhiNode(values[0].kind(), merge);
+        effects.addFloatingNode(phiNode);
+        for (int i = 0; i < values.length; i++) {
+            effects.addPhiInput(phiNode, values[i]);
+        }
+        readCache.put(new ReadCacheEntry(identity, phi), phiNode);
+    }
+
     public static BlockState meetAliases(List<BlockState> states) {
         BlockState newState = new BlockState();
 
@@ -201,6 +341,12 @@
                 }
             }
         }
+
         return newState;
     }
+
+    public Map<ReadCacheEntry, ValueNode> getReadCache() {
+        return readCache;
+    }
+
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java	Wed Apr 03 14:41:22 2013 +0200
@@ -53,8 +53,8 @@
                     try {
                         field.setAccessible(true);
                         str.append(str.length() > 0 ? ", " : "").append(name).append("=").append(format(field.get(this)));
-                    } catch (Exception e) {
-                        e.printStackTrace();
+                    } catch (SecurityException | IllegalAccessException e) {
+                        throw new RuntimeException(e);
                     }
                 }
             }
@@ -193,7 +193,7 @@
                 for (int i2 = 0; i2 < levelAt(i); i2++) {
                     str.append("    ");
                 }
-                str.append(effect).toString();
+                str.append(effect).append('\n');
             }
         }
         return str.toString();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Apr 03 14:41:22 2013 +0200
@@ -26,12 +26,55 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.virtual.nodes.*;
 
 public class GraphEffectList extends EffectList {
 
+    public void addCounterBefore(final String name, final int increment, final boolean addContext, final FixedNode position) {
+        if (!DynamicCounterNode.enabled) {
+            return;
+        }
+        add(new Effect() {
+
+            @Override
+            public String name() {
+                return "addCounterBefore";
+            }
+
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                assert position.isAlive();
+                DynamicCounterNode node = graph.add(new DynamicCounterNode(name, increment, addContext));
+                graph.addBeforeFixed(position, node);
+                node.setProbability(position.probability());
+            }
+        });
+    }
+
+    public void addSurvivingCounterBefore(final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) {
+        if (!DynamicCounterNode.enabled) {
+            return;
+        }
+        add(new Effect() {
+
+            @Override
+            public String name() {
+                return "addSurvivingCounterBefore";
+            }
+
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                assert position.isAlive();
+                DynamicCounterNode node = graph.add(new SurvivingCounterNode(name, increment, addContext, checkedValue));
+                graph.addBeforeFixed(position, node);
+                node.setProbability(position.probability());
+            }
+        });
+    }
+
     /**
      * Adds the given fixed node to the graph's control flow, before position (so that the original
      * predecessor of position will then be node's predecessor).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011, 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.virtual.phases.ea;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+
+public class IterativeInliningPhase extends Phase {
+
+    private final PhasePlan plan;
+
+    private final GraalCodeCacheProvider runtime;
+    private final Assumptions assumptions;
+    private final GraphCache cache;
+    private final OptimisticOptimizations optimisticOpts;
+
+    public IterativeInliningPhase(GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
+        this.runtime = runtime;
+        this.assumptions = assumptions;
+        this.cache = cache;
+        this.plan = plan;
+        this.optimisticOpts = optimisticOpts;
+    }
+
+    public static final void trace(String format, Object... obj) {
+        if (GraalOptions.TraceEscapeAnalysis) {
+            Debug.log(format, obj);
+        }
+    }
+
+    @Override
+    protected void run(final StructuredGraph graph) {
+        runIterations(graph, true);
+        runIterations(graph, false);
+    }
+
+    private void runIterations(final StructuredGraph graph, final boolean simple) {
+        Boolean continueIteration = true;
+        for (int iteration = 0; iteration < GraalOptions.EscapeAnalysisIterations && continueIteration; iteration++) {
+            continueIteration = Debug.scope("iteration " + iteration, new Callable<Boolean>() {
+
+                @Override
+                public Boolean call() {
+                    boolean progress = false;
+                    PartialEscapeAnalysisPhase ea = new PartialEscapeAnalysisPhase(runtime, assumptions, false);
+                    ea.apply(graph);
+                    progress |= ea.hasChanged();
+
+                    Map<Invoke, Double> hints = GraalOptions.PEAInliningHints ? PartialEscapeAnalysisPhase.getHints(graph) : null;
+
+                    InliningPhase inlining = new InliningPhase(runtime, hints, assumptions, cache, plan, optimisticOpts);
+                    inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE);
+                    inlining.apply(graph);
+                    progress |= inlining.getInliningCount() > 0;
+
+                    new DeadCodeEliminationPhase().apply(graph);
+
+                    if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) {
+                        new CanonicalizerPhase(runtime, assumptions).apply(graph);
+                        new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph);
+                    }
+
+                    return progress;
+                }
+            });
+        }
+    }
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Wed Apr 03 14:41:22 2013 +0200
@@ -30,12 +30,15 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.EffectList.Effect;
 
 public class PartialEscapeAnalysisPhase extends Phase {
@@ -45,12 +48,18 @@
     private CustomCanonicalizer customCanonicalizer;
     private final boolean iterative;
 
+    private boolean changed;
+
     public PartialEscapeAnalysisPhase(MetaAccessProvider runtime, Assumptions assumptions, boolean iterative) {
         this.runtime = runtime;
         this.assumptions = assumptions;
         this.iterative = iterative;
     }
 
+    public boolean hasChanged() {
+        return changed;
+    }
+
     public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) {
         this.customCanonicalizer = customCanonicalizer;
     }
@@ -61,25 +70,23 @@
         }
     }
 
-    public static final void error(String format, Object... obj) {
-        System.out.print(String.format(format, obj));
-    }
-
     @Override
     protected void run(final StructuredGraph graph) {
         if (!matches(graph, GraalOptions.EscapeAnalyzeOnly)) {
             return;
         }
 
-        boolean analyzableNodes = false;
-        for (Node node : graph.getNodes()) {
-            if (node instanceof VirtualizableAllocation) {
-                analyzableNodes = true;
-                break;
+        if (!GraalOptions.PEAReadCache) {
+            boolean analyzableNodes = false;
+            for (Node node : graph.getNodes()) {
+                if (node instanceof VirtualizableAllocation) {
+                    analyzableNodes = true;
+                    break;
+                }
             }
-        }
-        if (!analyzableNodes) {
-            return;
+            if (!analyzableNodes) {
+                return;
+            }
         }
 
         Boolean continueIteration = true;
@@ -88,14 +95,16 @@
 
                 @Override
                 public Boolean call() {
+
                     SchedulePhase schedule = new SchedulePhase();
                     schedule.apply(graph, false);
                     PartialEscapeClosure closure = new PartialEscapeClosure(graph.createNodeBitMap(), schedule, runtime, assumptions);
                     ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new BlockState(), null);
 
-                    if (closure.getNewVirtualObjectCount() == 0) {
+                    if (!closure.hasChanged()) {
                         return false;
                     }
+                    changed = true;
 
                     // apply the effects collected during the escape analysis iteration
                     ArrayList<Node> obsoleteNodes = new ArrayList<>();
@@ -104,20 +113,25 @@
                     }
                     trace("%s\n", closure.getEffects());
 
-                    Debug.dump(graph, "after PartialEscapeAnalysis");
+                    Debug.dump(graph, "after PartialEscapeAnalysis iteration");
                     assert noObsoleteNodes(graph, obsoleteNodes);
 
                     new DeadCodeEliminationPhase().apply(graph);
-                    if (!iterative) {
-                        return false;
-                    }
+
                     if (GraalOptions.OptCanonicalizer) {
                         new CanonicalizerPhase(runtime, assumptions, null, customCanonicalizer).apply(graph);
                     }
-                    return true;
+
+                    return iterative;
                 }
             });
         }
+
+        for (Node node : graph.getNodes()) {
+            if (node instanceof LoadFieldNode) {
+                DynamicCounterNode.addCounterBefore("load non-elim", 1, false, (FixedNode) node);
+            }
+        }
     }
 
     private static boolean matches(StructuredGraph graph, String filter) {
@@ -128,7 +142,7 @@
         return true;
     }
 
-    private static boolean noObsoleteNodes(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+    static boolean noObsoleteNodes(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
         // helper code that determines the paths that keep obsolete nodes alive:
 
         NodeFlood flood = graph.createNodeFlood();
@@ -153,7 +167,7 @@
 
         for (Node node : obsoleteNodes) {
             if (node instanceof FixedNode) {
-                assert !flood.isMarked(node);
+                assert !flood.isMarked(node) : node;
             }
         }
 
@@ -182,10 +196,10 @@
         boolean success = true;
         for (Node node : obsoleteNodes) {
             if (flood.isMarked(node)) {
-                error("offending node path:");
+                System.out.print("offending node path:");
                 Node current = node;
                 while (current != null) {
-                    error(current.toString());
+                    System.out.println(current.toString());
                     current = path.get(current);
                     if (current != null && current instanceof FixedNode && !obsoleteNodes.contains(current)) {
                         break;
@@ -196,4 +210,39 @@
         }
         return success;
     }
+
+    public static Map<Invoke, Double> getHints(StructuredGraph graph) {
+        Map<Invoke, Double> hints = null;
+        for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) {
+            double sum = 0;
+            double invokeSum = 0;
+            for (Node usage : materialize.usages()) {
+                if (usage instanceof FixedNode) {
+                    sum += ((FixedNode) usage).probability();
+                } else {
+                    if (usage instanceof MethodCallTargetNode) {
+                        invokeSum += ((MethodCallTargetNode) usage).invoke().probability();
+                    }
+                    for (Node secondLevelUage : materialize.usages()) {
+                        if (secondLevelUage instanceof FixedNode) {
+                            sum += ((FixedNode) secondLevelUage).probability();
+                        }
+                    }
+                }
+            }
+            // TODO(lstadler) get rid of this magic number
+            if (sum > 100 && invokeSum > 0) {
+                for (Node usage : materialize.usages()) {
+                    if (usage instanceof MethodCallTargetNode) {
+                        if (hints == null) {
+                            hints = new HashMap<>();
+                        }
+                        Invoke invoke = ((MethodCallTargetNode) usage).invoke();
+                        hints.put(invoke, sum / invokeSum);
+                    }
+                }
+            }
+        }
+        return hints;
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Apr 03 14:41:22 2013 +0200
@@ -34,14 +34,18 @@
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.nodes.*;
+import com.oracle.graal.virtual.phases.ea.BlockState.ReadCacheEntry;
 
 class PartialEscapeClosure extends BlockIteratorClosure<BlockState> {
 
@@ -53,6 +57,11 @@
     public static final DebugMetric METRIC_MATERIALIZATIONS_LOOP_END = Debug.metric("MaterializationsLoopEnd");
     public static final DebugMetric METRIC_ALLOCATION_REMOVED = Debug.metric("AllocationsRemoved");
 
+    public static final DebugMetric METRIC_STOREFIELD_RECORDED = Debug.metric("StoreFieldRecorded");
+    public static final DebugMetric METRIC_LOADFIELD_ELIMINATED = Debug.metric("LoadFieldEliminated");
+    public static final DebugMetric METRIC_LOADFIELD_NOT_ELIMINATED = Debug.metric("LoadFieldNotEliminated");
+    public static final DebugMetric METRIC_MEMORYCHECKOINT = Debug.metric("MemoryCheckpoint");
+
     private final NodeBitMap usages;
     private final SchedulePhase schedule;
 
@@ -60,12 +69,20 @@
 
     private final VirtualizerToolImpl tool;
 
+    private final Map<Invoke, Double> hints = new IdentityHashMap<>();
+
+    private boolean changed;
+
     public PartialEscapeClosure(NodeBitMap usages, SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
         this.usages = usages;
         this.schedule = schedule;
         tool = new VirtualizerToolImpl(effects, usages, metaAccess, assumptions);
     }
 
+    public boolean hasChanged() {
+        return changed;
+    }
+
     public GraphEffectList getEffects() {
         return effects;
     }
@@ -74,6 +91,10 @@
         return tool.getNewVirtualObjectCount();
     }
 
+    public Map<Invoke, Double> getHints() {
+        return hints;
+    }
+
     @Override
     protected void processBlock(Block block, BlockState state) {
         trace("\nBlock: %s (", block);
@@ -81,27 +102,68 @@
 
         FixedWithNextNode lastFixedNode = null;
         for (Node node : nodeList) {
+            boolean deleted;
             if (usages.isMarked(node) || node instanceof VirtualizableAllocation) {
                 trace("[[%s]] ", node);
-                processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state);
+                deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state);
             } else {
                 trace("%s ", node);
+                deleted = false;
             }
+            if (GraalOptions.PEAReadCache) {
+                if (!deleted) {
+                    if (node instanceof StoreFieldNode) {
+                        METRIC_STOREFIELD_RECORDED.increment();
+                        StoreFieldNode store = (StoreFieldNode) node;
+                        ValueNode cachedValue = state.getReadCache(store.object(), store.field());
+                        state.killReadCache(store.field());
 
-            if (node instanceof FixedWithNextNode && node.isAlive()) {
+                        if (cachedValue == store.value()) {
+                            effects.addCounterBefore("store elim", 1, false, lastFixedNode.next());
+                            effects.deleteFixedNode(store);
+                            changed = true;
+                        } else {
+                            state.addReadCache(store.object(), store.field(), store.value());
+                        }
+                    } else if (node instanceof LoadFieldNode) {
+                        LoadFieldNode load = (LoadFieldNode) node;
+                        ValueNode cachedValue = state.getReadCache(load.object(), load.field());
+                        if (cachedValue != null) {
+                            METRIC_LOADFIELD_ELIMINATED.increment();
+                            effects.addCounterBefore("load elim", 1, false, lastFixedNode.next());
+                            effects.replaceAtUsages(load, cachedValue);
+                            state.addScalarAlias(load, cachedValue);
+                            changed = true;
+                        } else {
+                            METRIC_LOADFIELD_NOT_ELIMINATED.increment();
+                            state.addReadCache(load.object(), load.field(), load);
+                        }
+                    } else if (node instanceof MemoryCheckpoint) {
+                        METRIC_MEMORYCHECKOINT.increment();
+                        MemoryCheckpoint checkpoint = (MemoryCheckpoint) node;
+                        for (Object identity : checkpoint.getLocationIdentities()) {
+                            state.killReadCache(identity);
+                        }
+                    }
+                }
+            }
+            if (node instanceof FixedWithNextNode) {
                 lastFixedNode = (FixedWithNextNode) node;
             }
         }
         trace(")\n    end state: %s\n", state);
     }
 
-    private void processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) {
+    private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) {
         tool.reset(state, node);
         if (node instanceof Virtualizable) {
             ((Virtualizable) node).virtualize(tool);
         }
         if (tool.isDeleted()) {
-            return;
+            if (tool.isCustomAction() || !(node instanceof VirtualizableAllocation || node instanceof CyclicMaterializeStoreNode)) {
+                changed = true;
+            }
+            return true;
         }
         if (node instanceof StateSplit) {
             StateSplit split = (StateSplit) node;
@@ -178,15 +240,20 @@
             }
         }
         if (tool.isCustomAction()) {
-            return;
+            return false;
         }
         for (ValueNode input : node.inputs().filter(ValueNode.class)) {
             ObjectState obj = state.getObjectState(input);
             if (obj != null) {
+                if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
+                    Invoke invoke = ((MethodCallTargetNode) node).invoke();
+                    hints.put(invoke, 5d);
+                }
                 trace("replacing input %s at %s: %s", input, node, obj);
                 replaceWithMaterialized(input, node, insertBefore, state, obj, METRIC_MATERIALIZATIONS_UNHANDLED);
             }
         }
+        return false;
     }
 
     private void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore, DebugMetric metric) {
@@ -207,7 +274,6 @@
 
     @Override
     protected BlockState merge(MergeNode merge, List<BlockState> states) {
-
         BlockState newState = BlockState.meetAliases(states);
 
         // Iterative processing:
@@ -300,13 +366,15 @@
                 }
             }
 
-            for (PhiNode phi : merge.phis().snapshot()) {
+            for (PhiNode phi : merge.phis()) {
                 if (usages.isMarked(phi) && phi.type() == PhiType.Value) {
                     materialized |= processPhi(newState, merge, phi, states);
                 }
             }
         } while (materialized);
 
+        newState.mergeReadCache(states, merge, effects);
+
         return newState;
     }
 
@@ -373,7 +441,7 @@
     }
 
     @Override
-    protected BlockState afterSplit(FixedNode node, BlockState oldState) {
+    protected BlockState cloneState(BlockState oldState) {
         return oldState.cloneState();
     }
 
@@ -421,11 +489,13 @@
             List<BlockState> loopEndStates = info.endStates;
             List<Block> predecessors = loop.header.getPredecessors();
             HashSet<VirtualObjectNode> additionalMaterializations = new HashSet<>();
+            HashSet<ReadCacheEntry> additionalKilledReads = new HashSet<>();
             int oldPhiCount = phis.size();
             for (int i = 1; i < predecessors.size(); i++) {
-                processLoopEnd(loop.loopBegin(), (LoopEndNode) predecessors.get(i).getEndNode(), state, loopEndStates.get(i - 1), successEffects, additionalMaterializations, phis);
+                processLoopEnd(loop.loopBegin(), (LoopEndNode) predecessors.get(i).getEndNode(), state, loopEndStates.get(i - 1), successEffects, additionalMaterializations, additionalKilledReads,
+                                phis);
             }
-            if (additionalMaterializations.isEmpty() && oldPhiCount == phis.size()) {
+            if (additionalMaterializations.isEmpty() && additionalKilledReads.isEmpty() && oldPhiCount == phis.size()) {
                 effects.addAll(successEffects);
 
                 assert info.exitStates.size() == loop.exits.size();
@@ -450,6 +520,9 @@
                         assert obj.getState() == EscapeState.Global;
                     }
                 }
+                for (ReadCacheEntry entry : additionalKilledReads) {
+                    initialState.getReadCache().remove(entry);
+                }
             }
         }
 
@@ -473,7 +546,7 @@
                     ObjectState valueObj = exitState.getObjectState(value);
                     if (valueObj == null) {
                         if ((value instanceof PhiNode && ((PhiNode) value).merge() == exitNode.loopBegin()) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
-                            ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value);
+                            ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
                             obj.setEntry(i, proxy);
                             effects.addFloatingNode(proxy);
                         }
@@ -483,7 +556,7 @@
                 if (initialObj == null || initialObj.isVirtual()) {
                     ProxyNode proxy = proxies.get(obj.virtual);
                     if (proxy == null) {
-                        proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value);
+                        proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value, null);
                         effects.addFloatingNode(proxy);
                     } else {
                         effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue());
@@ -492,10 +565,18 @@
                     obj.updateMaterializedValue(proxy);
                 } else {
                     assert initialObj.getMaterializedValue() == obj.getMaterializedValue() : "materialized value is not allowed to change within loops: " + initialObj.getMaterializedValue() +
-                                    " vs. " + obj.getMaterializedValue();
+                                    " vs. " + obj.getMaterializedValue() + " at " + exitNode;
                 }
             }
         }
+
+        for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
+            if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
+                ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null);
+                effects.addFloatingNode(proxy);
+                entry.setValue(proxy);
+            }
+        }
     }
 
     private final class PhiDesc {
@@ -530,7 +611,7 @@
     }
 
     private void processLoopEnd(LoopBeginNode loopBegin, LoopEndNode loopEnd, BlockState initialState, BlockState loopEndState, GraphEffectList successEffects,
-                    Set<VirtualObjectNode> additionalMaterializations, HashSet<PhiDesc> phis) {
+                    Set<VirtualObjectNode> additionalMaterializations, HashSet<ReadCacheEntry> additionalKilledReads, HashSet<PhiDesc> phis) {
         assert loopEnd.loopBegin() == loopBegin;
         boolean materialized;
         do {
@@ -573,7 +654,7 @@
                     }
                 }
             }
-            for (PhiNode phi : loopBegin.phis().snapshot()) {
+            for (PhiNode phi : loopBegin.phis()) {
                 if (usages.isMarked(phi) && phi.type() == PhiType.Value) {
                     ObjectState initialObj = initialState.getObjectState(phi.valueAt(0));
                     boolean initialMaterialized = initialObj == null || !initialObj.isVirtual();
@@ -662,5 +743,11 @@
                 }
             }
         }
+
+        for (Map.Entry<ReadCacheEntry, ValueNode> entry : initialState.getReadCache().entrySet()) {
+            if (loopEndState.getReadCache().get(entry.getKey()) != entry.getValue()) {
+                additionalKilledReads.add(entry.getKey());
+            }
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.BinaryNodeTestFactory.AddNodeFactory;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+
+import static junit.framework.Assert.*;
+import static com.oracle.truffle.api.codegen.test.TestHelper.*;
+
+public class BinaryNodeTest {
+
+    @Test
+    public void testAdd() {
+        TestRootNode<AddNode> node = create(AddNodeFactory.getInstance());
+        assertEquals(42, executeWith(node, 19, 23));
+        assertEquals(42d, executeWith(node, 19d, 23d));
+        assertEquals(42d, executeWith(node, "19", "23"));
+        assertEquals(42, executeWith(node, 19, 23));
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testAddUnsupported() {
+        TestRootNode<AddNode> node = create(AddNodeFactory.getInstance());
+        executeWith(node, new Object(), new Object());
+    }
+
+    abstract static class BinaryNode extends ValueNode {
+
+        @Child protected ValueNode leftNode;
+        @Child protected ValueNode rightNode;
+
+        public BinaryNode(ValueNode left, ValueNode right) {
+            this.leftNode = left;
+            this.rightNode = right;
+        }
+
+        public BinaryNode(BinaryNode prev) {
+            this(prev.leftNode, prev.rightNode);
+        }
+    }
+
+    abstract static class AddNode extends BinaryNode {
+
+        public AddNode(ValueNode left, ValueNode right) {
+            super(left, right);
+        }
+
+        public AddNode(AddNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        int add(int left, int right) {
+            return left + right;
+        }
+
+        @Generic
+        Object add(Object left, Object right) {
+            return convertDouble(left) + convertDouble(right);
+        }
+
+        static double convertDouble(Object value) {
+            if (value instanceof Number) {
+                return ((Number) value).doubleValue();
+            } else if (value instanceof String) {
+                return Double.parseDouble((String) value);
+            }
+            throw new RuntimeException("Invalid datatype");
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.codegen.test;
-
-import com.oracle.truffle.api.codegen.*;
-import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
-
-public class BinaryOperationTest {
-
-    static int convertInt(Object value) {
-        if (value instanceof Number) {
-            return ((Number) value).intValue();
-        } else if (value instanceof String) {
-            return Integer.parseInt((String) value);
-        }
-        throw new RuntimeException("Invalid datatype");
-    }
-
-    @NodeClass(BinaryNode.class)
-    abstract static class BinaryNode extends ValueNode {
-
-        @Child protected ValueNode leftNode;
-        @Child protected ValueNode rightNode;
-
-        public BinaryNode(ValueNode left, ValueNode right) {
-            this.leftNode = left;
-            this.rightNode = right;
-        }
-
-        public BinaryNode(BinaryNode prev) {
-            this(prev.leftNode, prev.rightNode);
-        }
-
-        @Specialization
-        int add(int left, int right) {
-            return left + right;
-        }
-
-        @Generic
-        int add(Object left, Object right) {
-            return convertInt(left) + convertInt(right);
-        }
-
-        @Specialization
-        int sub(int left, int right) {
-            return left + right;
-        }
-
-        @Generic
-        int sub(Object left, Object right) {
-            return convertInt(left) + convertInt(right);
-        }
-
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen.test;
+
+import static com.oracle.truffle.api.codegen.test.TestHelper.*;
+import static junit.framework.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrAccessContextFactory;
+import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrConcatFactory;
+import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrLengthFactory;
+import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrSubstrFactory;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ChildrenNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+
+public class BuiltinTest {
+
+    @Test
+    public void testConcat() {
+        TestRootNode<BuiltinNode> node = create(StrConcatFactory.getInstance(), new Context());
+        Str str1 = new Str("42");
+        Str str2 = new Str(" is the number.");
+        assertEquals(str1.concat(str2), executeWith(node, str1, str2));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testConcatUnsupported() {
+        TestRootNode<BuiltinNode> node = create(StrConcatFactory.getInstance(), new Context());
+        executeWith(node, 42, new Str(" is the number."));
+    }
+
+    @Test
+    public void testSubstrSpecialized() {
+        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        Str str = new Str("test 42");
+
+        assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7));
+    }
+
+    @Test
+    public void testSubstrGeneric() {
+        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        Str str = new Str("test 42");
+
+        assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7"));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSubstrUnsupported() {
+        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        executeWith(node, new Object(), "5", "7");
+    }
+
+    @Test
+    public void testLength() {
+        TestRootNode<BuiltinNode> node = create(StrLengthFactory.getInstance(), new Context());
+        Str testStr = new Str("test 42");
+        assertEquals(testStr.length(), executeWith(node, testStr));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLengthUnsupported() {
+        TestRootNode<BuiltinNode> node = create(StrLengthFactory.getInstance(), new Context());
+        executeWith(node, new Object());
+    }
+
+    @Test
+    public void testAccessContext() {
+        Context context = new Context();
+        TestRootNode<BuiltinNode> node = create(StrAccessContextFactory.getInstance(), context);
+        // accessible by node
+        assertSame(context, node.getNode().getContext());
+        // accessible by execution
+        assertSame(context, executeWith(node));
+    }
+
+    @NodeClass(BuiltinNode.class)
+    static class Str {
+
+        private final String internal;
+
+        public Str(String internal) {
+            this.internal = internal;
+        }
+
+        @Specialization
+        Str concat(Str s1) {
+            return new Str(internal + s1.internal);
+        }
+
+        @Specialization
+        Str substr(int beginIndex, int endIndex) {
+            return new Str(internal.substring(beginIndex, endIndex));
+        }
+
+        @Generic
+        static Str substr(Object thisValue, Object beginIndex, Object endIndex) {
+            if (!(thisValue instanceof Str)) {
+                throw new UnsupportedOperationException();
+            }
+            return ((Str) thisValue).substr(convertInt(beginIndex), convertInt(endIndex));
+        }
+
+        @Specialization
+        int length() {
+            return internal.length();
+        }
+
+        @Specialization
+        static Object accessContext(Context context) {
+            return context;
+        }
+
+        static int convertInt(Object value) {
+            if (value instanceof Number) {
+                return ((Number) value).intValue();
+            } else if (value instanceof String) {
+                return Integer.parseInt((String) value);
+            }
+            throw new RuntimeException("Invalid datatype");
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Str) {
+                return internal.equals(((Str) obj).internal);
+            }
+            return super.equals(obj);
+        }
+
+        @Override
+        public String toString() {
+            return internal;
+        }
+
+        @Override
+        public int hashCode() {
+            return internal.hashCode();
+        }
+    }
+
+    abstract static class BuiltinNode extends ChildrenNode {
+
+        protected final Context context;
+
+        public BuiltinNode(BuiltinNode node) {
+            this(node.context, node.children);
+        }
+
+        public BuiltinNode(Context context, ValueNode... children) {
+            super(children);
+            this.context = context;
+        }
+
+        public Context getContext() {
+            return context;
+        }
+
+    }
+
+    static class Context {
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen.test;
+
+import static com.oracle.truffle.api.codegen.test.TestHelper.*;
+import static junit.framework.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.GuardsTestFactory.GlobalFlagGuardFactory;
+import com.oracle.truffle.api.codegen.test.GuardsTestFactory.InvocationGuardFactory;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ChildrenNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+
+@SuppressWarnings("unused")
+public class GuardsTest {
+
+    private static final Object NULL = new Object();
+
+    @Test
+    public void testGuardInvocations() {
+        TestRootNode<InvocationGuard> root = create(InvocationGuardFactory.getInstance());
+
+        assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1, 1));
+        assertEquals(1, InvocationGuard.specializedInvocations);
+        assertEquals(0, InvocationGuard.genericInvocations);
+
+        assertEquals(42, executeWith(root, Integer.MAX_VALUE, 1));
+        assertEquals(1, InvocationGuard.specializedInvocations);
+        assertEquals(1, InvocationGuard.genericInvocations);
+    }
+
+    public abstract static class InvocationGuard extends ChildrenNode {
+
+        static int specializedInvocations = 0;
+        static int genericInvocations = 0;
+
+        public InvocationGuard(ValueNode... children) {
+            super(children);
+        }
+
+        public InvocationGuard(InvocationGuard node) {
+            super(node);
+        }
+
+        boolean guard(int value0, int value1) {
+            return value0 != Integer.MAX_VALUE;
+        }
+
+        @Specialization(guards = "guard")
+        int doSpecialized(int value0, int value1) {
+            specializedInvocations++;
+            return value0 + value1;
+        }
+
+        @Generic
+        int doGeneric(Object value0, Object value1) {
+            genericInvocations++;
+            return 42; // the generic answer to all questions
+        }
+    }
+
+    @Test
+    public void testGuardGlobal() {
+        TestRootNode<GlobalFlagGuard> root = create(GlobalFlagGuardFactory.getInstance());
+
+        assertEquals(42, executeWith(root, NULL));
+
+        GlobalFlagGuard.globalFlag = true;
+        assertEquals(41, executeWith(root, NULL));
+
+        GlobalFlagGuard.globalFlag = false;
+        assertEquals(42, executeWith(root, NULL));
+    }
+
+    public abstract static class GlobalFlagGuard extends ChildrenNode {
+
+        static boolean globalFlag = false;
+
+        public GlobalFlagGuard(ValueNode... children) {
+            super(children);
+        }
+
+        public GlobalFlagGuard(GlobalFlagGuard node) {
+            super(node);
+        }
+
+        static boolean globalFlagGuard() {
+            return globalFlag;
+        }
+
+        @Specialization(guards = "globalFlagGuard")
+        int doSpecialized(Object value0) {
+            return 41;
+        }
+
+        @Generic
+        int doGeneric(Object value0) {
+            return 42; // the generic answer to all questions
+        }
+    }
+
+}
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.codegen.test;
-
-import org.junit.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.codegen.*;
-import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
-import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
-
-public class RuntimeStringTest {
-
-    @Test
-    public void testSubstr() {
-        executeAndAssert(new RuntimeString("es"), "substr", new RuntimeString("test"), 1, 3);
-    }
-
-    @Test
-    public void testConcat() {
-        executeAndAssert(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"), new RuntimeString("concat"));
-    }
-
-    @Test(expected = ArrayIndexOutOfBoundsException.class)
-    public void testConcatFail() {
-        executeAndAssert(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"));
-    }
-
-    @Test
-    public void testFindMethodByMethodName() {
-        // TODO
-    }
-
-    private static void executeAndAssert(Object expectedResult, String name, Object... argumentsArray) {
-        ArgNode[] args = new ArgNode[argumentsArray.length];
-        for (int i = 0; i < args.length; i++) {
-            args[i] = new ArgNode(argumentsArray, i);
-        }
-
-        BuiltinNode node = null;
-        for (NodeFactory<BuiltinNode> nodeFactory : RuntimeStringTestFactory.getFactories()) {
-            GeneratedBy generated = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
-            Assert.assertNotNull(generated);
-            Assert.assertNotSame("", generated.methodName());
-            if (generated.methodName().equals(name)) {
-                node = nodeFactory.createNode((Object) args);
-                break;
-            }
-        }
-        Assert.assertNotNull("Node not found", node);
-        CallTarget target = Truffle.getRuntime().createCallTarget(new TestRootNode(node));
-        Assert.assertEquals(expectedResult, target.call());
-    }
-
-    static class ArgNode extends ValueNode {
-
-        final Object[] arguments;
-        final int index;
-
-        ArgNode(Object[] args, int index) {
-            this.arguments = args;
-            this.index = index;
-        }
-
-        @Override
-        Object execute() {
-            return arguments[index];
-        }
-
-    }
-
-    abstract static class BuiltinNode extends ValueNode {
-
-        @Children ArgNode[] parameters;
-
-        BuiltinNode(ArgNode[] parameters) {
-            this.parameters = adoptChildren(parameters);
-        }
-
-        BuiltinNode(BuiltinNode prev) {
-            this(prev.parameters);
-        }
-
-    }
-
-    @NodeClass(BuiltinNode.class)
-    static class RuntimeString {
-
-        private final String internal;
-
-        public RuntimeString(String internal) {
-            this.internal = internal;
-        }
-
-        @Specialization
-        static RuntimeString concat(RuntimeString s1, RuntimeString s2) {
-            return new RuntimeString(s1.internal + s2.internal);
-        }
-
-        @Specialization
-        RuntimeString substr(int beginIndex, int endIndex) {
-            return new RuntimeString(internal.substring(beginIndex, endIndex));
-        }
-
-        @Generic
-        RuntimeString substr(Object beginIndex, Object endIndex) {
-            return substr(convertInt(beginIndex), convertInt(endIndex));
-        }
-
-        static int convertInt(Object value) {
-            if (value instanceof Number) {
-                return ((Number) value).intValue();
-            } else if (value instanceof String) {
-                return Integer.parseInt((String) value);
-            }
-            throw new RuntimeException("Invalid datatype");
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof RuntimeString) {
-                return internal.equals(((RuntimeString) obj).internal);
-            }
-            return super.equals(obj);
-        }
-
-        @Override
-        public int hashCode() {
-            return internal.hashCode();
-        }
-
-        @Override
-        public String toString() {
-            return internal;
-        }
-
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen.test;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.*;
+
+/**
+ * Utility class to provide some test helper functions.
+ */
+class TestHelper {
+
+    private static ArgumentNode[] arguments(int count) {
+        ArgumentNode[] nodes = new ArgumentNode[count];
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = new ArgumentNode(i);
+        }
+        return nodes;
+    }
+
+    static <E extends ValueNode> TestRootNode<E> create(NodeFactory<E> factory, Object... constants) {
+        ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size());
+
+        List<Object> argumentList = new ArrayList<>();
+        argumentList.addAll(Arrays.asList(constants));
+        if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass())) {
+            argumentList.add(argumentNodes);
+        } else {
+            argumentList.addAll(Arrays.asList(argumentNodes));
+        }
+        return new TestRootNode<>(factory.createNode(argumentList.toArray(new Object[argumentList.size()])));
+    }
+
+    static <E> Object executeWith(TestRootNode<? extends ValueNode> node, Object... values) {
+        return Truffle.getRuntime().createCallTarget(node).call(new TestArguments(values));
+    }
+
+}
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Wed Apr 03 14:41:22 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,50 +22,97 @@
  */
 package com.oracle.truffle.api.codegen.test;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.codegen.*;
-import com.oracle.truffle.api.codegen.test.RuntimeStringTest.RuntimeString;
+import com.oracle.truffle.api.codegen.test.BuiltinTest.Str;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
 public class TypeSystemTest {
 
-    @TypeSystem({int.class, RuntimeString.class})
+    @TypeSystem({int.class, Str.class})
     static class SimpleTypes {
     }
 
     @TypeSystemReference(SimpleTypes.class)
     abstract static class ValueNode extends Node {
 
-        int executeInt() throws UnexpectedResultException {
-            return SimpleTypesGen.SIMPLETYPES.expectInteger(execute());
+        int executeInt(VirtualFrame frame) throws UnexpectedResultException {
+            return SimpleTypesGen.SIMPLETYPES.expectInteger(execute(frame));
+        }
+
+        Str executeStr(VirtualFrame frame) throws UnexpectedResultException {
+            return SimpleTypesGen.SIMPLETYPES.expectStr(execute(frame));
         }
 
-        RuntimeString executeString() {
-            return new RuntimeString(execute().toString());
+        abstract Object execute(VirtualFrame frame);
+    }
+
+    @TypeSystemReference(SimpleTypes.class)
+    abstract static class ChildrenNode extends ValueNode {
+
+        @Children protected ValueNode[] children;
+
+        public ChildrenNode(ValueNode... children) {
+            this.children = adoptChildren(children);
         }
 
-        @SuppressWarnings("static-method")
-        final long executeSpecial() {
-            return 42L;
+        public ChildrenNode(ChildrenNode node) {
+            this(node.children);
         }
 
-        abstract Object execute();
-
     }
 
     @TypeSystemReference(SimpleTypes.class)
-    static class TestRootNode extends RootNode {
+    static class TestRootNode<E extends ValueNode> extends RootNode {
 
-        @Child private ValueNode node;
+        @Child private E node;
 
-        public TestRootNode(ValueNode node) {
+        public TestRootNode(E node) {
             this.node = adoptChild(node);
         }
 
         @Override
         public Object execute(VirtualFrame frame) {
-            return node.execute();
+            return node.execute(frame);
+        }
+
+        public E getNode() {
+            return node;
         }
     }
 
+    static class TestArguments extends Arguments {
+
+        private final Object[] values;
+
+        public TestArguments(Object... values) {
+            this.values = values;
+        }
+
+        public Object[] getValues() {
+            return values;
+        }
+
+        public Object get(int index) {
+            return values[index];
+        }
+
+    }
+
+    static class ArgumentNode extends ValueNode {
+
+        final int index;
+
+        public ArgumentNode(int index) {
+            this.index = index;
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return ((TestArguments) frame.getArguments()).get(index);
+        }
+
+    }
+
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java	Wed Apr 03 14:41:22 2013 +0200
@@ -41,7 +41,7 @@
  *
  * <ul>
  * <li>What do I need to get started? {@link com.oracle.truffle.api.codegen.test.TypeSystemTest}</li>
- * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.RuntimeStringTest}</li>
+ * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.BuiltinTest}</li>
  * </ul>
  * </p>
  *
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Wed Apr 03 14:41:22 2013 +0200
@@ -86,12 +86,12 @@
 
     @Override
     public boolean getBoolean(FrameSlot slot) {
-        return (Boolean) get(slot, Float.class, UNDEFINED_BOOLEAN);
+        return (Boolean) get(slot, Boolean.class, UNDEFINED_BOOLEAN);
     }
 
     @Override
     public void setBoolean(FrameSlot slot, boolean value) {
-        set(slot, Float.class, value);
+        set(slot, Boolean.class, value);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -30,10 +30,9 @@
 
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
-public class ExecutableTypeMethodParser extends MethodParser<ExecutableTypeData> {
+public class ExecutableTypeMethodParser extends NodeMethodParser<ExecutableTypeData> {
 
     public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) {
         super(context, node);
@@ -43,15 +42,16 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
+
         List<TypeMirror> types = new ArrayList<>();
         types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors());
         types.add(getContext().getType(void.class));
 
-        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types, false, Cardinality.ONE);
-
-        List<ParameterSpec> parameters = new ArrayList<>();
-        parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
-        return new MethodSpec(new ArrayList<TypeMirror>(), returnTypeSpec, parameters);
+        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types);
+        returnTypeSpec.setSignature(true);
+        MethodSpec spec = new MethodSpec(returnTypeSpec);
+        spec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
+        return spec;
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -31,9 +31,8 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.*;
 
-public class GenericParser extends MethodParser<SpecializationData> {
+public class GenericParser extends NodeMethodParser<SpecializationData> {
 
     public GenericParser(ProcessorContext context, NodeData node) {
         super(context, node);
@@ -45,18 +44,20 @@
     }
 
     @Override
-    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, boolean optional) {
+    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) {
         List<ExecutableTypeData> execTypes = nodeData.findGenericExecutableTypes(getContext());
         List<TypeMirror> types = new ArrayList<>();
         for (ExecutableTypeData type : execTypes) {
             types.add(type.getType().getPrimitiveType());
         }
-        return new ParameterSpec(valueName, types, false, Cardinality.ONE);
+        ParameterSpec spec = new ParameterSpec(valueName, types);
+        spec.setSignature(true);
+        return spec;
     }
 
     @Override
     protected ParameterSpec createReturnParameterSpec() {
-        return super.createValueParameterSpec("returnValue", getNode(), false);
+        return super.createValueParameterSpec("returnValue", getNode());
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.codegen.processor.node;
-
-import java.util.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-
-import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
-import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
-
-public abstract class MethodParser<E extends TemplateMethod> extends TemplateMethodParser<NodeData, E> {
-
-    public MethodParser(ProcessorContext context, NodeData node) {
-        super(context, node);
-    }
-
-    public NodeData getNode() {
-        return template;
-    }
-
-    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, boolean optional) {
-        return new ParameterSpec(valueName, nodeData, optional, Cardinality.ONE);
-    }
-
-    protected ParameterSpec createReturnParameterSpec() {
-        return createValueParameterSpec("operation", getNode(), false);
-    }
-
-    @Override
-    public boolean isParsable(ExecutableElement method) {
-        return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
-    }
-
-    @SuppressWarnings("unused")
-    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) {
-        List<ParameterSpec> defaultParameters = new ArrayList<>();
-
-        if (getNode().supportsFrame()) {
-            defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
-        }
-
-        TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType();
-
-        List<TypeMirror> prefixTypes = new ArrayList<>();
-
-        if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) {
-            prefixTypes.add(getNode().getTemplateType().asType());
-        }
-
-        for (NodeFieldData field : getNode().getFields()) {
-            if (field.getKind() == FieldKind.FIELD) {
-                ParameterSpec spec = new ParameterSpec(field.getName(), field.getType(), true);
-                spec.setLocal(true);
-                defaultParameters.add(spec);
-            }
-        }
-
-        for (NodeFieldData field : getNode().getFields()) {
-            if (field.getExecutionKind() == ExecutionKind.IGNORE) {
-                continue;
-            }
-
-            if (field.getExecutionKind() == ExecutionKind.DEFAULT) {
-                ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData(), false);
-                if (field.getKind() == FieldKind.CHILDREN) {
-                    spec.setCardinality(Cardinality.MULTIPLE);
-                    spec.setIndexed(true);
-                }
-                defaultParameters.add(spec);
-            } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
-                String valueName = field.getName();
-                if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
-                    break;
-                }
-
-                defaultParameters.add(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class), false));
-                defaultParameters.add(createValueParameterSpec(valueName, field.getNodeData(), false));
-            } else {
-                assert false;
-            }
-        }
-
-        return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters);
-    }
-
-    private static String shortCircuitValueName(String valueName) {
-        return "has" + Utils.firstLetterUpperCase(valueName);
-    }
-
-}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Apr 03 14:41:22 2013 +0200
@@ -117,24 +117,28 @@
         }
     }
 
-    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod target, TemplateMethod sourceMethod, TemplateMethod castMethod, String unexpectedValueName) {
+    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
         CodeTreeBuilder builder = parent.create();
 
-        boolean castedValues = sourceMethod != castMethod;
+        boolean castedValues = sourceMethod != targetMethod;
 
         builder.startGroup();
-        ExecutableElement method = target.getMethod();
+        ExecutableElement method = targetMethod.getMethod();
         if (method == null) {
-            throw new IllegalStateException("Cannot call synthtetic operation methods.");
+            throw new IllegalStateException("Cannot call synthetic operation methods.");
         }
         TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
-        NodeData node = (NodeData) castMethod.getTemplate();
+        NodeData node = (NodeData) targetMethod.getTemplate();
         TypeSystemData typeSystem = node.getTypeSystem();
 
-        boolean accessible = target.canBeAccessedByInstanceOf(node.getNodeType());
+        boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType());
         if (accessible) {
             if (builder.findMethod().getModifiers().contains(STATIC)) {
-                builder.string(THIS_NODE_LOCAL_VAR_NAME);
+                if (method.getModifiers().contains(STATIC)) {
+                    builder.type(targetClass.asType());
+                } else {
+                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
+                }
             } else {
                 builder.string("super");
             }
@@ -143,8 +147,8 @@
                 builder.type(targetClass.asType());
             } else {
                 ActualParameter parameter = null;
-                for (ActualParameter searchParameter : target.getParameters()) {
-                    if (!searchParameter.getSpecification().isOptional()) {
+                for (ActualParameter searchParameter : targetMethod.getParameters()) {
+                    if (searchParameter.getSpecification().isSignature()) {
                         parameter = searchParameter;
                         break;
                     }
@@ -172,10 +176,10 @@
         builder.string(".");
         builder.startCall(method.getSimpleName().toString());
 
-        for (ActualParameter targetParameter : castMethod.getParameters()) {
+        for (ActualParameter targetParameter : targetMethod.getParameters()) {
             ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName());
             if (valueParameter == null) {
-                continue;
+                valueParameter = targetParameter;
             }
             TypeData targetType = targetParameter.getActualTypeData(typeSystem);
 
@@ -257,12 +261,34 @@
         body.string(".").startCall(methodName);
     }
 
-    private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization,
+    private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues,
                     CodeTree guardedStatements, CodeTree elseStatements) {
 
+        NodeData node = targetSpecialization.getNode();
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, valueSpecialization, guardedSpecialization);
-        CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, valueSpecialization, guardedSpecialization, onSpecialization);
+        CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization);
+        CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization);
+
+        Set<String> valuesNeedsCast;
+        if (castValues) {
+            // cast all
+            valuesNeedsCast = null;
+        } else {
+            // find out which values needs a cast
+            valuesNeedsCast = new HashSet<>();
+            for (GuardData guard : targetSpecialization.getGuards()) {
+                for (ActualParameter parameter : guard.getParameters()) {
+                    NodeFieldData field = node.findField(parameter.getSpecification().getName());
+                    if (field == null) {
+                        continue;
+                    }
+                    TypeData typeData = parameter.getActualTypeData(node.getTypeSystem());
+                    if (typeData != null && !typeData.isGeneric()) {
+                        valuesNeedsCast.add(parameter.getLocalName());
+                    }
+                }
+            }
+        }
 
         int ifCount = 0;
 
@@ -274,9 +300,7 @@
             ifCount++;
         }
 
-        if (explicitGuards != null || !onSpecialization) {
-            builder.tree(createCasts(parent, valueSpecialization, guardedSpecialization));
-        }
+        builder.tree(createCasts(parent, valuesNeedsCast, sourceSpecialization, targetSpecialization));
 
         if (explicitGuards != null) {
             builder.startIf();
@@ -302,24 +326,22 @@
         return builder.getRoot();
     }
 
-    private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization) {
+    private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         if (guardedSpecialization.getGuards().size() > 0) {
             // Explicitly specified guards
-            for (SpecializationGuardData guard : guardedSpecialization.getGuards()) {
-                if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) {
-                    builder.string(andOperator);
-                    builder.tree(createTemplateMethodCall(parent, guard.getGuardDeclaration(), valueSpecialization, guardedSpecialization, null));
-                    andOperator = " && ";
-                }
+            for (GuardData guard : guardedSpecialization.getGuards()) {
+                builder.string(andOperator);
+                builder.tree(createTemplateMethodCall(parent, valueSpecialization, guard, null));
+                andOperator = " && ";
             }
         }
 
         return builder.isEmpty() ? null : builder.getRoot();
     }
 
-    private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+    private CodeTree createCasts(CodeTreeBuilder parent, Set<String> castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
@@ -329,6 +351,10 @@
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
 
+            if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) {
+                continue;
+            }
+
             CodeTree cast = createCast(parent, field, valueParam, guardedParam);
             if (cast == null) {
                 continue;
@@ -945,7 +971,7 @@
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
             method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addInternalValueParameters(method, node.getGenericSpecialization(), false);
+            addInternalValueParameters(method, node.getGenericSpecialization(), true);
 
             CodeTreeBuilder body = method.createBuilder();
             body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
@@ -959,7 +985,7 @@
                 guarded.string(THIS_NODE_LOCAL_VAR_NAME);
                 guarded.end().end();
 
-                body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null));
+                body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded.getRoot(), null));
             }
             body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
 
@@ -1015,7 +1041,7 @@
                 addInternalValueParameterNames(nextBuilder, next, null, true, true);
                 nextBuilder.end().end();
 
-                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, nextBuilder.getRoot());
+                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot());
             }
 
             builder.tree(invokeMethod);
@@ -1034,7 +1060,7 @@
                 emitEncounteredSynthetic(builder);
             } else {
                 builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, specialization, specialization.getNode().getGenericSpecialization(), specialization, null));
+                builder.tree(createTemplateMethodCall(builder, specialization.getNode().getGenericSpecialization(), specialization, null));
                 builder.end(); // return
             }
 
@@ -1204,7 +1230,7 @@
             if (next != null) {
                 returnSpecialized = createReturnSpecializeAndExecute(builder, next, null);
             }
-            builder.tree(createGuardAndCast(builder, null, specialization, specialization, false, executeNode, returnSpecialized));
+            builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized));
         }
 
         private CodeTree createDeoptimize(CodeTreeBuilder parent) {
@@ -1227,7 +1253,7 @@
                 builder.startCall(factoryClassName(node), "specialize");
                 builder.string("this");
                 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addInternalValueParameterNames(builder, specialization, null, false, true);
+                addInternalValueParameterNames(builder, specialization, null, true, true);
                 builder.end(); // call replace, call specialize
             } else {
                 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
@@ -1265,7 +1291,7 @@
                 builder.end().end();
             } else {
                 builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, specialization, specialization, specialization, null));
+                builder.tree(createTemplateMethodCall(builder, specialization, specialization, null));
                 builder.end(); // return
             }
 
@@ -1296,7 +1322,7 @@
         private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
             for (TemplateMethod listener : node.getSpecializationListeners()) {
                 builder.startStatement();
-                builder.tree(createTemplateMethodCall(builder, listener, listener, listener, null));
+                builder.tree(createTemplateMethodCall(builder, listener, listener, null));
                 builder.end(); // statement
             }
         }
@@ -1392,7 +1418,7 @@
             builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
 
-            builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
+            builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
 
             builder.end(); // statement
 
@@ -1445,7 +1471,7 @@
             builder.startStatement();
             builder.startCall("replace");
             builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true);
+            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, true, true);
             builder.end();
             builder.end(); // call replace
             builder.end(); // statement
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Apr 03 14:41:22 2013 +0200
@@ -187,22 +187,11 @@
 
         methods.addAll(getSpecializationListeners());
         methods.addAll(getExecutableTypes());
-        methods.addAll(getGuards());
         methods.addAll(getShortCircuits());
 
         return methods;
     }
 
-    public List<GuardData> findGuards(String name) {
-        List<GuardData> foundGuards = new ArrayList<>();
-        for (GuardData guardData : getGuards()) {
-            if (guardData.getMethodName().equals(name)) {
-                foundGuards.add(guardData);
-            }
-        }
-        return foundGuards;
-    }
-
     public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) {
         List<ExecutableTypeData> types = findGenericExecutableTypes(context);
         for (ExecutableTypeData availableType : types) {
@@ -312,6 +301,7 @@
         return null;
     }
 
+    @Override
     public TypeSystemData getTypeSystem() {
         return typeSystem;
     }
@@ -323,7 +313,7 @@
     private String dump(int level) {
         String indent = "";
         for (int i = 0; i < level; i++) {
-            indent += "  ";
+            indent += "    ";
         }
         StringBuilder builder = new StringBuilder();
 
@@ -334,7 +324,6 @@
         dumpProperty(builder, indent, "fields", getFields());
         dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
         dumpProperty(builder, indent, "specializations", getSpecializations());
-        dumpProperty(builder, indent, "guards", getGuards());
         dumpProperty(builder, indent, "messages", collectMessages());
         if (getDeclaredChildren().size() > 0) {
             builder.append(String.format("\n%s  children = [", indent));
@@ -352,7 +341,7 @@
         if (value instanceof List) {
             List<?> list = (List<?>) value;
             if (!list.isEmpty()) {
-                b.append(String.format("\n%s  %s = %s", indent, propertyName, dumpList((List<?>) value)));
+                b.append(String.format("\n%s  %s = %s", indent, propertyName, dumpList(indent, (List<?>) value)));
             }
         } else {
             if (value != null) {
@@ -361,7 +350,7 @@
         }
     }
 
-    private static String dumpList(List<?> array) {
+    private static String dumpList(String indent, List<?> array) {
         if (array == null) {
             return "null";
         }
@@ -375,12 +364,12 @@
         StringBuilder b = new StringBuilder();
         b.append("[");
         for (Object object : array) {
-            b.append("\n");
-            b.append("    ");
+            b.append("\n        ");
+            b.append(indent);
             b.append(object);
             b.append(", ");
         }
-        b.append("\n  ]");
+        b.append("\n    ").append(indent).append("]");
         return b.toString();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.node;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
+import com.oracle.truffle.codegen.processor.template.*;
+import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+
+public abstract class NodeMethodParser<E extends TemplateMethod> extends TemplateMethodParser<NodeData, E> {
+
+    public NodeMethodParser(ProcessorContext context, NodeData node) {
+        super(context, node);
+    }
+
+    public NodeData getNode() {
+        return template;
+    }
+
+    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) {
+        ParameterSpec spec = new ParameterSpec(valueName, nodeTypeMirrors(nodeData));
+        spec.setSignature(true);
+        return spec;
+    }
+
+    private static List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
+        Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
+
+        for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) {
+            typeMirrors.add(typeData.getType().getPrimitiveType());
+        }
+
+        typeMirrors.add(nodeData.getTypeSystem().getGenericType());
+
+        return new ArrayList<>(typeMirrors);
+    }
+
+    protected ParameterSpec createReturnParameterSpec() {
+        return createValueParameterSpec("operation", getNode());
+    }
+
+    @Override
+    public boolean isParsable(ExecutableElement method) {
+        return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
+    }
+
+    @SuppressWarnings("unused")
+    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) {
+        MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec());
+
+        if (getNode().supportsFrame()) {
+            methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
+        }
+
+        resolveAndAddImplicitThis(methodSpec, method);
+
+        for (NodeFieldData field : getNode().getFields()) {
+            if (field.getKind() == FieldKind.FIELD) {
+                ParameterSpec spec = new ParameterSpec(field.getName(), field.getType());
+                spec.setLocal(true);
+                methodSpec.addOptional(spec);
+            }
+        }
+
+        for (NodeFieldData field : getNode().getFields()) {
+            if (field.getExecutionKind() == ExecutionKind.IGNORE) {
+                continue;
+            }
+
+            if (field.getExecutionKind() == ExecutionKind.DEFAULT) {
+                ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData());
+                if (field.getKind() == FieldKind.CHILDREN) {
+                    spec.setCardinality(Cardinality.MULTIPLE);
+                    spec.setIndexed(true);
+                }
+                methodSpec.addRequired(spec);
+            } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
+                String valueName = field.getName();
+                if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
+                    break;
+                }
+
+                methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
+                methodSpec.addRequired(createValueParameterSpec(valueName, field.getNodeData()));
+            } else {
+                assert false;
+            }
+        }
+
+        return methodSpec;
+    }
+
+    protected void resolveAndAddImplicitThis(MethodSpec methodSpec, ExecutableElement method) {
+        TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType();
+
+        if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, getContext().getTruffleTypes().getNode())) {
+            methodSpec.addImplicitRequiredType(getNode().getTemplateType().asType());
+        }
+    }
+
+    private static String shortCircuitValueName(String valueName) {
+        return "has" + Utils.firstLetterUpperCase(valueName);
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -186,7 +186,7 @@
         }
 
         for (NodeData splittedNode : nodes) {
-            finalizeSpecializations(splittedNode);
+            finalizeSpecializations(elements, splittedNode);
             verifyNode(splittedNode);
         }
 
@@ -254,7 +254,6 @@
     }
 
     private void parseMethods(final NodeData node, List<Element> elements) {
-        node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements));
         node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements));
         node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements));
         List<SpecializationData> generics = new GenericParser(context, node).parse(elements);
@@ -267,13 +266,17 @@
         node.setSpecializations(allSpecializations);
     }
 
-    private void finalizeSpecializations(final NodeData node) {
+    private void finalizeSpecializations(List<Element> elements, final NodeData node) {
         List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
 
         if (specializations.isEmpty()) {
             return;
         }
 
+        for (SpecializationData specialization : specializations) {
+            matchGuards(elements, specialization);
+        }
+
         List<SpecializationData> generics = new ArrayList<>();
         for (SpecializationData spec : specializations) {
             if (spec.isGeneric()) {
@@ -332,13 +335,7 @@
             specializations.add(new SpecializationData(uninializedMethod, false, true));
         }
 
-        Collections.sort(specializations, new Comparator<SpecializationData>() {
-
-            @Override
-            public int compare(SpecializationData o1, SpecializationData o2) {
-                return compareSpecialization(node.getTypeSystem(), o1, o2);
-            }
-        });
+        Collections.sort(specializations);
 
         node.setSpecializations(specializations);
 
@@ -358,6 +355,31 @@
         }
     }
 
+    private void matchGuards(List<Element> elements, SpecializationData specialization) {
+        if (specialization.getGuardDefinitions().isEmpty()) {
+            specialization.setGuards(Collections.<GuardData> emptyList());
+            return;
+        }
+
+        List<GuardData> foundGuards = new ArrayList<>();
+        List<ExecutableElement> methods = ElementFilter.methodsIn(elements);
+        for (String guardDefinition : specialization.getGuardDefinitions()) {
+            GuardParser parser = new GuardParser(context, specialization, guardDefinition);
+            List<GuardData> guards = parser.parse(methods);
+            if (!guards.isEmpty()) {
+                foundGuards.add(guards.get(0));
+            } else {
+                // error no guard found
+                MethodSpec spec = parser.createSpecification(specialization.getMethod(), null);
+                spec.applyTypeDefinitions("types");
+                specialization.addError("Guard with method name '%s' not found. Expected signature: %n%s", guardDefinition, spec.toSignatureString("guard"));
+            }
+        }
+
+        specialization.setGuards(foundGuards);
+
+    }
+
     private static List<String> calculateSpecializationIds(List<SpecializationData> specializations) {
         int lastSize = -1;
         List<List<String>> signatureChunks = new ArrayList<>();
@@ -531,17 +553,17 @@
         boolean valid = true;
         int args = -1;
         for (SpecializationData specializationData : nodeData.getSpecializations()) {
-            int specializationArgs = 0;
+            int signatureArgs = 0;
             for (ActualParameter param : specializationData.getParameters()) {
-                if (!param.getSpecification().isOptional()) {
-                    specializationArgs++;
+                if (param.getSpecification().isSignature()) {
+                    signatureArgs++;
                 }
             }
-            if (args != -1 && args != specializationArgs) {
+            if (args != -1 && args != signatureArgs) {
                 valid = false;
                 break;
             }
-            args = specializationArgs;
+            args = signatureArgs;
         }
         if (!valid) {
             for (SpecializationData specialization : nodeData.getSpecializations()) {
@@ -717,7 +739,11 @@
 
         NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution);
         if (type != null && mirror != null) {
-            NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(type));
+            TypeElement typeElement = Utils.fromTypeMirror(type);
+            if (typeElement == null) {
+                return null;
+            }
+            NodeData fieldNodeData = resolveNode(typeElement);
             fieldData.setNode(fieldNodeData);
 
             if (fieldNodeData == null) {
@@ -927,14 +953,12 @@
     }
 
     private static void verifySpecializationOrder(NodeData node) {
-        TypeSystemData typeSystem = node.getTypeSystem();
         List<SpecializationData> specializations = node.getSpecializations();
-
         for (int i = 0; i < specializations.size(); i++) {
             SpecializationData m1 = specializations.get(i);
             for (int j = i + 1; j < specializations.size(); j++) {
                 SpecializationData m2 = specializations.get(j);
-                int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2);
+                int inferredOrder = m1.compareBySignature(m2);
 
                 if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) {
                     int specOrder = m1.getOrder() - m2.getOrder();
@@ -974,72 +998,6 @@
         }
     }
 
-    private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) {
-        if (m1 == m2) {
-            return 0;
-        }
-        int result = compareSpecializationWithoutOrder(typeSystem, m1, m2);
-        if (result == 0) {
-            if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) {
-                return m1.getOrder() - m2.getOrder();
-            }
-        }
-        return result;
-    }
-
-    private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) {
-        if (m1 == m2) {
-            return 0;
-        }
-
-        if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) {
-            return m1.getOrder() - m2.getOrder();
-        } else if (m1.isUninitialized() && !m2.isUninitialized()) {
-            return -1;
-        } else if (!m1.isUninitialized() && m2.isUninitialized()) {
-            return 1;
-        } else if (m1.isGeneric() && !m2.isGeneric()) {
-            return 1;
-        } else if (!m1.isGeneric() && m2.isGeneric()) {
-            return -1;
-        }
-
-        if (m1.getTemplate() != m2.getTemplate()) {
-            throw new UnsupportedOperationException("Cannot compare two specializations with different templates.");
-        }
-
-        int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType());
-
-        for (ActualParameter p1 : m1.getParameters()) {
-            NodeFieldData field = m1.getNode().findField(p1.getSpecification().getName());
-            if (field == null) {
-                continue;
-            }
-            ActualParameter p2 = m2.findParameter(p1.getLocalName());
-
-            if (p1 != null && p2 != null && !Utils.typeEquals(p1.getActualType(), p2.getActualType())) {
-                int typeResult = compareActualParameter(typeSystem, p1, p2);
-                if (result == 0) {
-                    result = typeResult;
-                } else if (Math.signum(result) != Math.signum(typeResult)) {
-                    // We cannot define an order.
-                    return 0;
-                }
-            }
-        }
-        return result;
-    }
-
-    private static int compareActualParameter(TypeSystemData typeSystem, ActualParameter p1, ActualParameter p2) {
-        int index1 = typeSystem.findType(p1.getActualType());
-        int index2 = typeSystem.findType(p2.getActualType());
-
-        assert index1 != index2;
-        assert !(index1 == -1 ^ index2 == -1);
-
-        return index1 - index2;
-    }
-
     @Override
     public Class<? extends Annotation> getAnnotationType() {
         return null;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -32,7 +32,7 @@
 import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 
-public class ShortCircuitParser extends MethodParser<ShortCircuitData> {
+public class ShortCircuitParser extends NodeMethodParser<ShortCircuitData> {
 
     private final Set<String> shortCircuitValues;
 
@@ -54,7 +54,7 @@
 
     @Override
     protected ParameterSpec createReturnParameterSpec() {
-        return new ParameterSpec("has", getContext().getType(boolean.class), false);
+        return new ParameterSpec("has", getContext().getType(boolean.class));
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Wed Apr 03 14:41:22 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
 import com.oracle.truffle.codegen.processor.template.*;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class SpecializationData extends TemplateMethod {
 
@@ -35,7 +36,8 @@
     private final boolean generic;
     private final boolean uninitialized;
     private final List<SpecializationThrowsData> exceptions;
-    private List<SpecializationGuardData> guards;
+    private List<String> guardDefinitions = Collections.emptyList();
+    private List<GuardData> guards;
     private List<ShortCircuitData> shortCircuits;
     private boolean useSpecializationsForGeneric = true;
     private NodeData node;
@@ -93,6 +95,31 @@
         return false;
     }
 
+    @Override
+    public int compareBySignature(TemplateMethod other) {
+        if (this == other) {
+            return 0;
+        } else if (!(other instanceof SpecializationData)) {
+            return super.compareBySignature(other);
+        }
+
+        SpecializationData m2 = (SpecializationData) other;
+
+        if (getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) {
+            return getOrder() - m2.getOrder();
+        } else if (isUninitialized() ^ m2.isUninitialized()) {
+            return isUninitialized() ? -1 : 1;
+        } else if (isGeneric() ^ m2.isGeneric()) {
+            return isGeneric() ? 1 : -1;
+        }
+
+        if (getTemplate() != m2.getTemplate()) {
+            throw new UnsupportedOperationException("Cannot compare two specializations with different templates.");
+        }
+
+        return super.compareBySignature(m2);
+    }
+
     public NodeData getNode() {
         return node;
     }
@@ -101,10 +128,14 @@
         this.node = node;
     }
 
-    public void setGuards(List<SpecializationGuardData> guards) {
+    public void setGuards(List<GuardData> guards) {
         this.guards = guards;
     }
 
+    public void setGuardDefinitions(List<String> guardDefinitions) {
+        this.guardDefinitions = guardDefinitions;
+    }
+
     public int getOrder() {
         return order;
     }
@@ -121,7 +152,11 @@
         return exceptions;
     }
 
-    public List<SpecializationGuardData> getGuards() {
+    public List<String> getGuardDefinitions() {
+        return guardDefinitions;
+    }
+
+    public List<GuardData> getGuards() {
         return guards;
     }
 
@@ -152,12 +187,11 @@
     }
 
     public boolean hasDynamicGuards() {
-        for (SpecializationGuardData guard : getGuards()) {
-            if (guard.isOnExecution()) {
-                return true;
-            }
-        }
-        return false;
+        return !getGuards().isEmpty();
     }
 
+    @Override
+    public String toString() {
+        return String.format("%s [id = %s, method = %s, guards = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards());
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -30,7 +30,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
-public class SpecializationListenerParser extends MethodParser<SpecializationListenerData> {
+public class SpecializationListenerParser extends NodeMethodParser<SpecializationListenerData> {
 
     public SpecializationListenerParser(ProcessorContext context, NodeData node) {
         super(context, node);
@@ -43,7 +43,7 @@
 
     @Override
     protected ParameterSpec createReturnParameterSpec() {
-        return new ParameterSpec("void", getContext().getType(void.class), false);
+        return new ParameterSpec("void", getContext().getType(void.class));
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -31,9 +31,8 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.typesystem.*;
 
-public class SpecializationMethodParser extends MethodParser<SpecializationData> {
+public class SpecializationMethodParser extends NodeMethodParser<SpecializationData> {
 
     public SpecializationMethodParser(ProcessorContext context, NodeData operation) {
         super(context, operation);
@@ -54,7 +53,7 @@
         return Specialization.class;
     }
 
-    private SpecializationData parseSpecialization(TemplateMethod method) {
+    private static SpecializationData parseSpecialization(TemplateMethod method) {
         int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order");
         if (order < 0 && order != Specialization.DEFAULT_ORDER) {
             method.addError("Invalid order attribute %d. The value must be >= 0 or the default value.");
@@ -80,76 +79,10 @@
             }
         });
         SpecializationData specialization = new SpecializationData(method, order, exceptionData);
-        AnnotationValue guardsValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "guards");
         List<String> guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
-        List<SpecializationGuardData> guardData = new ArrayList<>(guardDefs.size());
-        for (int i = 0; i < guardDefs.size(); i++) {
-            String guardMethod = guardDefs.get(i);
-
-            SpecializationGuardData assignedGuard = new SpecializationGuardData(specialization, guardsValue, guardMethod, true, true);
-
-            guardData.add(assignedGuard);
-
-            GuardData compatibleGuard = matchSpecializationGuard(specialization, assignedGuard);
-            if (compatibleGuard != null) {
-                assignedGuard.setGuardDeclaration(compatibleGuard);
-            }
-        }
-
-        specialization.setGuards(guardData);
+        specialization.setGuardDefinitions(guardDefs);
 
         return specialization;
     }
 
-    private GuardData matchSpecializationGuard(SpecializationData specialization, SpecializationGuardData specializationGuard) {
-        List<GuardData> foundGuards = getNode().findGuards(specializationGuard.getGuardMethod());
-
-        GuardData compatibleGuard = null;
-        for (GuardData guardData : foundGuards) {
-            if (isGuardCompatible(specialization, guardData)) {
-                compatibleGuard = guardData;
-                break;
-            }
-        }
-
-        if (compatibleGuard == null) {
-            ParameterSpec returnTypeSpec = new ParameterSpec("returnValue", getContext().getType(boolean.class), false);
-            List<ParameterSpec> expectedParameterSpecs = new ArrayList<>();
-
-            for (ActualParameter param : specialization.getParameters()) {
-                ParameterSpec spec = param.getSpecification();
-                expectedParameterSpecs.add(new ParameterSpec(spec.getName(), param.getActualType(), false));
-            }
-            List<TypeDef> typeDefs = createTypeDefinitions(returnTypeSpec, expectedParameterSpecs);
-            String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs, typeDefs);
-            specializationGuard.addError("No guard with signature '%s' found in type system.", expectedSignature);
-        }
-
-        return compatibleGuard;
-    }
-
-    private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) {
-        Iterator<ActualParameter> guardParameters = guard.getParameters().iterator();
-        for (ActualParameter param : specialization.getParameters()) {
-            if (param.getSpecification().isOptional()) {
-                continue;
-            }
-            if (!guardParameters.hasNext()) {
-                return false;
-            }
-            ActualParameter guardParam = guardParameters.next();
-            if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType()) && !guardParam.getSpecification().isOptional()) {
-                return false;
-            }
-        }
-        while (guardParameters.hasNext()) {
-            ActualParameter param = guardParameters.next();
-            if (!param.getSpecification().isOptional()) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Wed Apr 03 14:41:22 2013 +0200
@@ -26,33 +26,74 @@
 
 import javax.lang.model.type.*;
 
+import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+
 public class MethodSpec {
 
-    private final List<TypeMirror> implicitTypes;
+    private final List<TypeMirror> implicitRequiredTypes = new ArrayList<>();
 
     private final ParameterSpec returnType;
-    private final List<ParameterSpec> parameters;
+    private final List<ParameterSpec> optional = new ArrayList<>();
+    private final List<ParameterSpec> required = new ArrayList<>();
+
+    private boolean variableRequiredArguments;
+    private List<TypeDef> typeDefinitions;
 
-    public MethodSpec(List<TypeMirror> prefixTypes, ParameterSpec returnType, List<ParameterSpec> parameters) {
-        this.implicitTypes = prefixTypes;
+    public MethodSpec(ParameterSpec returnType) {
         this.returnType = returnType;
-        this.parameters = parameters;
+    }
+
+    public void setVariableRequiredArguments(boolean variableArguments) {
+        this.variableRequiredArguments = variableArguments;
     }
 
-    public List<TypeMirror> getImplicitTypes() {
-        return implicitTypes;
+    public boolean isVariableRequiredArguments() {
+        return variableRequiredArguments;
+    }
+
+    public void addImplicitRequiredType(TypeMirror type) {
+        this.implicitRequiredTypes.add(type);
+    }
+
+    public void addOptional(ParameterSpec spec) {
+        optional.add(spec);
+    }
+
+    public void addRequired(ParameterSpec spec) {
+        required.add(spec);
+    }
+
+    public List<TypeMirror> getImplicitRequiredTypes() {
+        return implicitRequiredTypes;
     }
 
     public ParameterSpec getReturnType() {
         return returnType;
     }
 
-    public List<ParameterSpec> getParameters() {
-        return parameters;
+    public List<ParameterSpec> getRequired() {
+        return required;
+    }
+
+    public List<ParameterSpec> getOptional() {
+        return optional;
+    }
+
+    public void makeTypeDefinitions() {
+
+    }
+
+    public List<ParameterSpec> getAll() {
+        List<ParameterSpec> specs = new ArrayList<>();
+        specs.add(getReturnType());
+        specs.addAll(getOptional());
+        specs.addAll(getRequired());
+        return specs;
     }
 
     public ParameterSpec findParameterSpec(String name) {
-        for (ParameterSpec spec : parameters) {
+        for (ParameterSpec spec : getAll()) {
             if (spec.getName().equals(name)) {
                 return spec;
             }
@@ -60,4 +101,131 @@
         return null;
     }
 
+    public void applyTypeDefinitions(String prefix) {
+        this.typeDefinitions = createTypeDefinitions(prefix);
+    }
+
+    private List<TypeDef> createTypeDefinitions(String prefix) {
+        List<TypeDef> typeDefs = new ArrayList<>();
+
+        int defIndex = 0;
+        for (ParameterSpec spec : getAll()) {
+            List<TypeMirror> allowedTypes = spec.getAllowedTypes();
+            List<TypeMirror> types = spec.getAllowedTypes();
+            if (types != null && allowedTypes.size() > 1) {
+                TypeDef foundDef = null;
+                for (TypeDef def : typeDefs) {
+                    if (allowedTypes.equals(def.getTypes())) {
+                        foundDef = def;
+                        break;
+                    }
+                }
+                if (foundDef == null) {
+                    foundDef = new TypeDef(types, prefix + defIndex);
+                    typeDefs.add(foundDef);
+                    defIndex++;
+                }
+
+                spec.setTypeDefinition(foundDef);
+            }
+        }
+
+        return typeDefs;
+    }
+
+    public String toSignatureString(String methodName) {
+        StringBuilder b = new StringBuilder();
+        b.append("    ");
+        b.append(createTypeSignature(returnType, true));
+
+        b.append(" ");
+        b.append(methodName);
+        b.append("(");
+
+        String sep = "";
+
+        for (ParameterSpec optionalSpec : getOptional()) {
+            b.append(sep);
+            b.append("[");
+            b.append(createTypeSignature(optionalSpec, false));
+            b.append("]");
+            sep = ", ";
+        }
+
+        for (ParameterSpec requiredSpec : getRequired()) {
+            b.append(sep);
+            if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) {
+                b.append("{");
+            }
+            b.append(createTypeSignature(requiredSpec, false));
+            if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) {
+                b.append("}");
+            }
+            sep = ", ";
+        }
+
+        b.append(")");
+
+        if (typeDefinitions != null && !typeDefinitions.isEmpty()) {
+            b.append("\n\n");
+
+            String lineSep = "";
+            for (TypeDef def : typeDefinitions) {
+                b.append(lineSep);
+                b.append("    <").append(def.getName()).append(">");
+                b.append(" = {");
+                String separator = "";
+                for (TypeMirror type : def.getTypes()) {
+                    b.append(separator).append(Utils.getSimpleName(type));
+                    separator = ", ";
+                }
+                b.append("}");
+                lineSep = "\n";
+
+            }
+        }
+        return b.toString();
+    }
+
+    private static String createTypeSignature(ParameterSpec spec, boolean typeOnly) {
+        StringBuilder builder = new StringBuilder();
+        TypeDef foundTypeDef = spec.getTypeDefinition();
+        if (foundTypeDef != null) {
+            builder.append("<" + foundTypeDef.getName() + ">");
+        } else if (spec.getAllowedTypes().size() >= 1) {
+            builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0)));
+        } else {
+            builder.append("void");
+        }
+        if (!typeOnly) {
+            builder.append(" ");
+            builder.append(spec.getName());
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public String toString() {
+        return toSignatureString("methodName");
+    }
+
+    static class TypeDef {
+
+        private final List<TypeMirror> types;
+        private final String name;
+
+        public TypeDef(List<TypeMirror> types, String name) {
+            this.types = types;
+            this.name = name;
+        }
+
+        public List<TypeMirror> getTypes() {
+            return types;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Wed Apr 03 14:41:22 2013 +0200
@@ -27,8 +27,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.*;
-import com.oracle.truffle.codegen.processor.typesystem.*;
+import com.oracle.truffle.codegen.processor.template.MethodSpec.TypeDef;
 
 public class ParameterSpec {
 
@@ -38,37 +37,47 @@
 
     private final String name;
     private final List<TypeMirror> allowedTypes;
-    private final boolean optional;
-    private Cardinality cardinality;
+
+    /** Cardinality one or multiple. */
+    private Cardinality cardinality = Cardinality.ONE;
+    /** Type is part of the method signature. Relevant for comparisons. */
+    private boolean signature;
+    /** Type must be indexed when parsing. */
     private boolean indexed;
+    /** Type is bound to local final variable. */
     private boolean local;
 
-    public ParameterSpec(String name, List<TypeMirror> allowedTypes, boolean optional, Cardinality cardinality) {
-        this.allowedTypes = allowedTypes;
-        this.name = name;
-        this.optional = optional;
-        this.cardinality = cardinality;
+    private TypeDef typeDefinition;
+
+    public ParameterSpec(String name, TypeMirror... allowedTypes) {
+        this(name, Arrays.asList(allowedTypes));
     }
 
-    /** Type constructor. */
-    public ParameterSpec(String name, TypeMirror singleFixedType, boolean optional) {
-        this(name, Arrays.asList(singleFixedType), optional, Cardinality.ONE);
+    public ParameterSpec(String name, List<TypeMirror> allowedTypes) {
+        this.name = name;
+        this.allowedTypes = allowedTypes;
     }
 
-    /** Type system value constructor. */
-    public ParameterSpec(String name, TypeSystemData typeSystem, boolean optional, Cardinality cardinality) {
-        this(name, typeSystem.getPrimitiveTypeMirrors(), optional, cardinality);
+    void setTypeDefinition(TypeDef typeDefinition) {
+        this.typeDefinition = typeDefinition;
     }
 
-    /** Node value constructor. */
-    public ParameterSpec(String name, NodeData nodeData, boolean optional, Cardinality cardinality) {
-        this(name, nodeTypeMirrors(nodeData), optional, cardinality);
+    TypeDef getTypeDefinition() {
+        return typeDefinition;
+    }
+
+    public void setSignature(boolean signature) {
+        this.signature = signature;
     }
 
     public void setLocal(boolean local) {
         this.local = local;
     }
 
+    public boolean isSignature() {
+        return signature;
+    }
+
     public boolean isLocal() {
         return local;
     }
@@ -85,27 +94,11 @@
         this.cardinality = cardinality;
     }
 
-    private static List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
-        Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
-
-        for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) {
-            typeMirrors.add(typeData.getType().getPrimitiveType());
-        }
-
-        typeMirrors.add(nodeData.getTypeSystem().getGenericType());
-
-        return new ArrayList<>(typeMirrors);
-    }
-
-    public final String getName() {
+    public String getName() {
         return name;
     }
 
-    public final boolean isOptional() {
-        return optional;
-    }
-
-    public final Cardinality getCardinality() {
+    public Cardinality getCardinality() {
         return cardinality;
     }
 
@@ -122,4 +115,25 @@
         return false;
     }
 
+    @Override
+    public String toString() {
+        return toSignatureString(false);
+    }
+
+    public String toSignatureString(boolean typeOnly) {
+        StringBuilder builder = new StringBuilder();
+        if (typeDefinition != null) {
+            builder.append("<" + typeDefinition.getName() + ">");
+        } else if (getAllowedTypes().size() >= 1) {
+            builder.append(Utils.getSimpleName(getAllowedTypes().get(0)));
+        } else {
+            builder.append("void");
+        }
+        if (!typeOnly) {
+            builder.append(" ");
+            builder.append(getName());
+        }
+        return builder.toString();
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Wed Apr 03 14:41:22 2013 +0200
@@ -28,6 +28,7 @@
 
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.api.element.*;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public abstract class Template extends MessageContainer {
 
@@ -43,6 +44,8 @@
         this.annotation = annotation;
     }
 
+    public abstract TypeSystemData getTypeSystem();
+
     @Override
     public Element getMessageElement() {
         return templateType;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Apr 03 14:41:22 2013 +0200
@@ -28,8 +28,12 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
-public class TemplateMethod extends MessageContainer {
+/**
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ */
+public class TemplateMethod extends MessageContainer implements Comparable<TemplateMethod> {
 
     private String id;
     private final Template template;
@@ -37,7 +41,7 @@
     private final ExecutableElement method;
     private final AnnotationMirror markerAnnotation;
     private final ActualParameter returnType;
-    private final List<ActualParameter> parameters;
+    private List<ActualParameter> parameters;
 
     public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType,
                     List<ActualParameter> parameters) {
@@ -61,6 +65,10 @@
         getMessages().addAll(method.getMessages());
     }
 
+    public void setParameters(List<ActualParameter> parameters) {
+        this.parameters = parameters;
+    }
+
     @Override
     public Element getMessageElement() {
         return method;
@@ -96,6 +104,16 @@
         return returnType;
     }
 
+    public List<ActualParameter> getRequiredParameters() {
+        List<ActualParameter> requiredParameters = new ArrayList<>();
+        for (ActualParameter parameter : getParameters()) {
+            if (getSpecification().getRequired().contains(parameter.getSpecification())) {
+                requiredParameters.add(parameter);
+            }
+        }
+        return requiredParameters;
+    }
+
     public List<ActualParameter> getParameters() {
         return parameters;
     }
@@ -116,15 +134,6 @@
         return Collections.unmodifiableList(allParameters);
     }
 
-    public ActualParameter findParameter(ParameterSpec spec) {
-        for (ActualParameter param : getParameters()) {
-            if (param.getSpecification().getName().equals(spec.getName())) {
-                return param;
-            }
-        }
-        return null;
-    }
-
     public boolean canBeAccessedByInstanceOf(TypeMirror type) {
         TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType();
         return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type);
@@ -148,7 +157,7 @@
 
     @Override
     public String toString() {
-        return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]";
+        return String.format("%s [id = %s, method = %s]", getClass().getSimpleName(), getId(), getMethod());
     }
 
     public ActualParameter getPreviousParam(ActualParameter searchParam) {
@@ -161,4 +170,71 @@
         }
         return prev;
     }
+
+    public List<TypeData> getSignature(TypeSystemData typeSystem) {
+        List<TypeData> types = new ArrayList<>();
+        for (ActualParameter parameter : getReturnTypeAndParameters()) {
+            if (!parameter.getSpecification().isSignature()) {
+                continue;
+            }
+            TypeData typeData = parameter.getActualTypeData(typeSystem);
+            if (typeData != null) {
+                types.add(typeData);
+            }
+        }
+        return types;
+    }
+
+    @Override
+    public int compareTo(TemplateMethod o) {
+        if (this == o) {
+            return 0;
+        }
+
+        int compare = compareBySignature(o);
+        if (compare == 0) {
+            // if signature sorting failed sort by id
+            compare = getId().compareTo(o.getId());
+        }
+        if (compare == 0) {
+            // if still no difference sort by enclosing type name
+            TypeElement enclosingType1 = Utils.findNearestEnclosingType(getMethod());
+            TypeElement enclosingType2 = Utils.findNearestEnclosingType(o.getMethod());
+            compare = enclosingType1.getQualifiedName().toString().compareTo(enclosingType2.getQualifiedName().toString());
+        }
+        return compare;
+    }
+
+    public int compareBySignature(TemplateMethod compareMethod) {
+        TypeSystemData typeSystem = getTemplate().getTypeSystem();
+        if (typeSystem != compareMethod.getTemplate().getTypeSystem()) {
+            throw new IllegalStateException("Cannot compare two methods with different type systems.");
+        }
+
+        List<TypeData> signature1 = getSignature(typeSystem);
+        List<TypeData> signature2 = compareMethod.getSignature(typeSystem);
+        if (signature1.size() != signature2.size()) {
+            return signature2.size() - signature1.size();
+        }
+
+        int result = 0;
+        for (int i = 0; i < signature1.size(); i++) {
+            int typeResult = compareActualParameter(typeSystem, signature1.get(i), signature2.get(i));
+            if (result == 0) {
+                result = typeResult;
+            } else if (typeResult != 0 && Math.signum(result) != Math.signum(typeResult)) {
+                // We cannot define an order.
+                return 0;
+            }
+        }
+
+        return result;
+    }
+
+    private static int compareActualParameter(TypeSystemData typeSystem, TypeData t1, TypeData t2) {
+        int index1 = typeSystem.findType(t1);
+        int index2 = typeSystem.findType(t2);
+        return index1 - index2;
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -110,13 +110,7 @@
                 valid = false;
             }
         }
-        Collections.sort(parsedMethods, new Comparator<TemplateMethod>() {
-
-            @Override
-            public int compare(TemplateMethod o1, TemplateMethod o2) {
-                return o1.getMethodName().compareTo(o2.getMethodName());
-            }
-        });
+        Collections.sort(parsedMethods);
 
         if (!valid && parseNullOnError) {
             return null;
@@ -130,27 +124,25 @@
             return null;
         }
 
+        methodSpecification.applyTypeDefinitions("types");
+
         String id = method.getSimpleName().toString();
         AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class);
         if (idAnnotation != null) {
             id = Utils.getAnnotationValue(String.class, idAnnotation, "value");
         }
 
-        List<TypeDef> typeDefs = createTypeDefinitions(methodSpecification.getReturnType(), methodSpecification.getParameters());
-
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
-        List<ParameterSpec> parameterSpecs = new ArrayList<>();
-        parameterSpecs.addAll(methodSpecification.getParameters());
 
         ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false);
         if (returnTypeMirror == null) {
             if (emitErrors) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()));
-                String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true);
+                String expectedReturnType = returnTypeSpec.toSignatureString(true);
                 String actualReturnType = Utils.getSimpleName(method.getReturnType());
 
                 String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType,
-                                createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
+                                methodSpecification.toSignatureString(method.getSimpleName().toString()));
                 invalidMethod.addError(message);
                 return invalidMethod;
             } else {
@@ -163,12 +155,12 @@
             parameterTypes.add(var.asType());
         }
 
-        List<ActualParameter> parameters = parseParameters(parameterTypes, methodSpecification.getImplicitTypes(), parameterSpecs);
+        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes);
         if (parameters == null) {
             if (isEmitErrors()) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()));
                 String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method),
-                                createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
+                                methodSpecification.toSignatureString(method.getSimpleName().toString()));
                 invalidMethod.addError(message);
                 return invalidMethod;
             } else {
@@ -180,87 +172,95 @@
     }
 
     private static String createActualSignature(MethodSpec spec, ExecutableElement method) {
-        List<String> types = new ArrayList<>();
-        for (TypeMirror implicitType : spec.getImplicitTypes()) {
-            types.add("implicit " + Utils.getSimpleName(implicitType));
+        StringBuilder b = new StringBuilder("(");
+        String sep = "";
+        for (TypeMirror implicitType : spec.getImplicitRequiredTypes()) {
+            b.append(sep);
+            b.append("implicit " + Utils.getSimpleName(implicitType));
+            sep = ", ";
         }
         for (VariableElement var : method.getParameters()) {
-            types.add(Utils.getSimpleName(var.asType()));
-        }
-
-        StringBuilder b = new StringBuilder("(");
-        for (Iterator<String> iterator = types.iterator(); iterator.hasNext();) {
-            b.append(iterator.next());
-            if (iterator.hasNext()) {
-                b.append(", ");
-            }
+            b.append(sep);
+            b.append(Utils.getSimpleName(var.asType()));
+            sep = ", ";
         }
         b.append(")");
         return b.toString();
     }
 
-    private List<ActualParameter> parseParameters(List<TypeMirror> types, List<TypeMirror> implicitTypes, List<ParameterSpec> parameterSpecs) {
-        Iterator<? extends TypeMirror> parameterIterator = types.iterator();
-        Iterator<? extends TypeMirror> implicitParametersIterator = implicitTypes.iterator();
-        Iterator<? extends ParameterSpec> specificationIterator = parameterSpecs.iterator();
+    private List<ActualParameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes) {
+        List<ActualParameter> parsedParams = new ArrayList<>();
+        ConsumableListIterator<TypeMirror> types = new ConsumableListIterator<>(parameterTypes);
 
-        TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
-        TypeMirror implicitParameter = implicitParametersIterator.hasNext() ? implicitParametersIterator.next() : null;
-        ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
+        // parse optional parameters
+        ConsumableListIterator<ParameterSpec> optionals = new ConsumableListIterator<>(spec.getOptional());
+        for (TypeMirror type : types) {
+            int oldIndex = types.getIndex();
+            int optionalCount = 1;
+            for (ParameterSpec paramspec : optionals) {
+                ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, false);
+                if (optionalParam != null) {
+                    optionals.consume(optionalCount);
+                    types.consume();
+                    parsedParams.add(optionalParam);
+                    break;
+                }
+                optionalCount++;
+            }
+            if (oldIndex == types.getIndex()) {
+                // nothing found anymore skip optional
+                break;
+            }
+        }
+
+        List<TypeMirror> typesWithImplicit = new ArrayList<>(spec.getImplicitRequiredTypes());
+        typesWithImplicit.addAll(types.toList());
+        types = new ConsumableListIterator<>(typesWithImplicit);
 
         int specificationParameterIndex = 0;
-        List<ActualParameter> resolvedParameters = new ArrayList<>();
-        while (parameter != null || specification != null || implicitParameter != null) {
-            if (parameter == null || specification == null) {
-                if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) {
-                    specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
+        ConsumableListIterator<ParameterSpec> required = new ConsumableListIterator<>(spec.getRequired());
+        while (required.get() != null || types.get() != null) {
+            if (required.get() == null || types.get() == null) {
+                if (required.get() != null && required.get().getCardinality() == Cardinality.MULTIPLE) {
+                    required.consume();
                     specificationParameterIndex = 0;
                     continue;
                 }
-                return null;
+                break;
             }
-
-            ActualParameter resolvedParameter = null;
-
-            boolean implicit = false;
-            if (implicitParameter != null) {
-                resolvedParameter = matchParameter(specification, implicitParameter, template, specificationParameterIndex, true);
-                if (resolvedParameter != null) {
-                    implicit = true;
-                }
-            }
-
-            if (resolvedParameter == null) {
-                resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, false);
-            }
-
+            boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size();
+            ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit);
             if (resolvedParameter == null) {
-                // mismatch
-                if (specification.isOptional()) {
-                    specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
-                    specificationParameterIndex = 0;
-                } else {
-                    return null;
+                if (required.get().getCardinality() == Cardinality.MULTIPLE) {
+                    required.consume();
+                    continue;
                 }
+                // direct mismatch but required -> error
+                return null;
             } else {
-                resolvedParameters.add(resolvedParameter);
-
-                // match
-                if (implicit) {
-                    implicitParameter = implicitParametersIterator.hasNext() ? implicitParametersIterator.next() : null;
-                } else {
-                    parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
-                }
-
-                if (specification.getCardinality() == Cardinality.ONE) {
-                    specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
+                parsedParams.add(resolvedParameter);
+                types.consume();
+                if (required.get().getCardinality() == Cardinality.ONE) {
+                    required.consume();
                     specificationParameterIndex = 0;
-                } else if (specification.getCardinality() == Cardinality.MULTIPLE) {
+                } else if (required.get().getCardinality() == Cardinality.MULTIPLE) {
                     specificationParameterIndex++;
                 }
             }
         }
-        return resolvedParameters;
+
+        if (!types.toList().isEmpty()) {
+            // additional types -> error
+            return null;
+        }
+
+        if (!required.toList().isEmpty() && !spec.isVariableRequiredArguments()) {
+            // additional specifications -> error
+            return null;
+        }
+
+        // success!
+        return parsedParams;
     }
 
     private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean implicit) {
@@ -275,143 +275,53 @@
         return new ActualParameter(specification, resolvedType, index, implicit);
     }
 
-    protected List<TypeDef> createTypeDefinitions(ParameterSpec returnType, List<? extends ParameterSpec> parameters) {
-        List<TypeDef> typeDefs = new ArrayList<>();
+    /* Helper class for parsing. */
+    private static class ConsumableListIterator<E> implements Iterable<E> {
 
-        List<ParameterSpec> allParams = new ArrayList<>();
-        allParams.add(returnType);
-        allParams.addAll(parameters);
+        private final List<E> data;
+        private int index;
+
+        public ConsumableListIterator(List<E> data) {
+            this.data = data;
+        }
 
-        int defIndex = 0;
-        for (ParameterSpec spec : allParams) {
-            List<TypeMirror> allowedTypes = spec.getAllowedTypes();
-            List<TypeMirror> types = spec.getAllowedTypes();
-            if (types != null && allowedTypes.size() > 1) {
-                TypeDef foundDef = null;
-                for (TypeDef def : typeDefs) {
-                    if (allowedTypes.equals(def.getTypes())) {
-                        foundDef = def;
-                        break;
-                    }
-                }
-                if (foundDef == null) {
-                    foundDef = new TypeDef(types, "Types" + defIndex);
-                    typeDefs.add(foundDef);
-                    defIndex++;
-                }
+        public E get() {
+            if (index >= data.size()) {
+                return null;
+            }
+            return data.get(index);
+        }
 
-                foundDef.getParameters().add(spec);
+        public E consume() {
+            return consume(1);
+        }
+
+        public E consume(int count) {
+            if (index + count <= data.size()) {
+                index += count;
+                return get();
+            } else {
+                throw new ArrayIndexOutOfBoundsException(count + 1);
             }
         }
 
-        return typeDefs;
-    }
-
-    protected static class TypeDef {
-
-        private final List<TypeMirror> types;
-        private final String name;
-        private final List<ParameterSpec> parameters = new ArrayList<>();
-
-        public TypeDef(List<TypeMirror> types, String name) {
-            this.types = types;
-            this.name = name;
+        public int getIndex() {
+            return index;
         }
 
-        public List<ParameterSpec> getParameters() {
-            return parameters;
-        }
-
-        public List<TypeMirror> getTypes() {
-            return types;
+        @Override
+        public Iterator<E> iterator() {
+            return toList().iterator();
         }
 
-        public String getName() {
-            return name;
-        }
-    }
-
-    public static String createExpectedSignature(String methodName, ParameterSpec returnType, List<? extends ParameterSpec> parameters, List<TypeDef> typeDefs) {
-        StringBuilder b = new StringBuilder();
-
-        b.append("    ");
-        b.append(createTypeSignature(returnType, typeDefs, true));
-
-        b.append(" ");
-        b.append(methodName);
-        b.append("(");
-
-        for (int i = 0; i < parameters.size(); i++) {
-            ParameterSpec specification = parameters.get(i);
-            if (specification.isOptional()) {
-                b.append("[");
+        public List<E> toList() {
+            if (index < data.size()) {
+                return data.subList(index, data.size());
+            } else {
+                return Collections.<E> emptyList();
             }
-            if (specification.getCardinality() == Cardinality.MULTIPLE) {
-                b.append("{");
-            }
-
-            b.append(createTypeSignature(specification, typeDefs, false));
-
-            if (specification.isOptional()) {
-                b.append("]");
-            }
-
-            if (specification.getCardinality() == Cardinality.MULTIPLE) {
-                b.append("}");
-            }
-
-            if (i < parameters.size() - 1) {
-                b.append(", ");
-            }
-
         }
 
-        b.append(")");
-
-        if (!typeDefs.isEmpty()) {
-            b.append("\n\n");
-
-            String lineSep = "";
-            for (TypeDef def : typeDefs) {
-                b.append(lineSep);
-                b.append("    <").append(def.getName()).append(">");
-                b.append(" = {");
-                String separator = "";
-                for (TypeMirror type : def.getTypes()) {
-                    b.append(separator).append(Utils.getSimpleName(type));
-                    separator = ", ";
-                }
-                b.append("}");
-                lineSep = "\n";
-
-            }
-        }
-        return b.toString();
-    }
-
-    private static String createTypeSignature(ParameterSpec spec, List<TypeDef> typeDefs, boolean typeOnly) {
-        StringBuilder builder = new StringBuilder();
-        if (spec.getAllowedTypes().size() > 1) {
-            TypeDef foundTypeDef = null;
-            for (TypeDef typeDef : typeDefs) {
-                if (typeDef.getParameters().contains(spec)) {
-                    foundTypeDef = typeDef;
-                    break;
-                }
-            }
-            if (foundTypeDef != null) {
-                builder.append("<" + foundTypeDef.getName() + ">");
-            }
-        } else if (spec.getAllowedTypes().size() == 1) {
-            builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0)));
-        } else {
-            builder.append("void");
-        }
-        if (!typeOnly) {
-            builder.append(" ");
-            builder.append(spec.getName());
-        }
-        return builder.toString();
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Wed Apr 03 14:41:22 2013 +0200
@@ -22,12 +22,20 @@
  */
 package com.oracle.truffle.codegen.processor.typesystem;
 
+import com.oracle.truffle.codegen.processor.node.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
 public class GuardData extends TemplateMethod {
 
-    public GuardData(TemplateMethod method) {
+    private final SpecializationData specialization;
+
+    public GuardData(TemplateMethod method, SpecializationData specialization) {
         super(method);
+        this.specialization = specialization;
+    }
+
+    public SpecializationData getSpecialization() {
+        return specialization;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -26,39 +26,68 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
-import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.node.*;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
-public class GuardParser extends TemplateMethodParser<Template, GuardData> {
+public class GuardParser extends NodeMethodParser<GuardData> {
 
-    private final TypeSystemData typeSystem;
+    private final SpecializationData specialization;
+    private final String guardName;
 
-    public GuardParser(ProcessorContext context, Template template, TypeSystemData typeSystem) {
-        super(context, template);
-        this.typeSystem = typeSystem;
+    public GuardParser(ProcessorContext context, SpecializationData specialization, String guardName) {
+        super(context, specialization.getNode());
+        this.specialization = specialization;
+        this.guardName = guardName;
         setEmitErrors(false);
         setParseNullOnError(false);
     }
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        List<ParameterSpec> specs = new ArrayList<>();
-        specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE));
-        ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false);
-        return new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
+        MethodSpec spec = createDefaultMethodSpec(method, mirror, null);
+        spec.setVariableRequiredArguments(true);
+        spec.getRequired().clear();
+
+        for (ActualParameter parameter : specialization.getRequiredParameters()) {
+            ParameterSpec paramSpec = new ParameterSpec(parameter.getLocalName(), parameter.getActualType(), getNode().getTypeSystem().getGenericType());
+            paramSpec.setSignature(true);
+            spec.addRequired(paramSpec);
+        }
+
+        return spec;
+    }
+
+    @Override
+    protected ParameterSpec createReturnParameterSpec() {
+        return new ParameterSpec("returnType", getContext().getType(boolean.class));
     }
 
     @Override
     public boolean isParsable(ExecutableElement method) {
-        return true;
+        return method.getSimpleName().toString().equals(guardName);
     }
 
     @Override
     public GuardData create(TemplateMethod method) {
-        return new GuardData(method);
+        GuardData guard = new GuardData(method, specialization);
+        /*
+         * Update parameters in way that parameter specifications match again the node field names
+         * etc.
+         */
+        List<ActualParameter> newParameters = new ArrayList<>();
+        for (ActualParameter parameter : guard.getParameters()) {
+            ActualParameter specializationParameter = specialization.findParameter(parameter.getSpecification().getName());
+            if (specializationParameter == null) {
+                newParameters.add(parameter);
+            } else {
+                newParameters.add(new ActualParameter(specializationParameter.getSpecification(), parameter.getActualType(), specializationParameter.getIndex(), parameter.isImplicit()));
+            }
+        }
+        guard.setParameters(newParameters);
+
+        return guard;
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -23,15 +23,12 @@
 package com.oracle.truffle.codegen.processor.typesystem;
 
 import java.lang.annotation.*;
-import java.util.*;
 
 import javax.lang.model.element.*;
-import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
 class TypeCastParser extends TypeSystemMethodParser<TypeCastData> {
 
@@ -45,10 +42,8 @@
         if (targetType == null) {
             return null;
         }
-        List<ParameterSpec> specs = new ArrayList<>();
-        specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE));
-        ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false);
-        MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
+        MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetType.getPrimitiveType()));
+        spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors()));
         return spec;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Wed Apr 03 14:41:22 2013 +0200
@@ -23,15 +23,12 @@
 package com.oracle.truffle.codegen.processor.typesystem;
 
 import java.lang.annotation.*;
-import java.util.*;
 
 import javax.lang.model.element.*;
-import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
 class TypeCheckParser extends TypeSystemMethodParser<TypeCheckData> {
 
@@ -45,10 +42,8 @@
         if (targetType == null) {
             return null;
         }
-        List<ParameterSpec> specs = new ArrayList<>();
-        specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE));
-        ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false);
-        MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
+        MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class)));
+        spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors()));
         return spec;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Thu Mar 28 17:11:06 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Wed Apr 03 14:41:22 2013 +0200
@@ -43,6 +43,11 @@
         super(templateType, null, annotation);
     }
 
+    @Override
+    public TypeSystemData getTypeSystem() {
+        return this;
+    }
+
     void setTypes(List<TypeData> types) {
         this.types = types;
         if (types != null) {
--- a/mx/commands.py	Thu Mar 28 17:11:06 2013 +0100
+++ b/mx/commands.py	Wed Apr 03 14:41:22 2013 +0200
@@ -690,8 +690,8 @@
         # Exclude all compiler tests and snippets
         excludes = ['com.oracle.graal.compiler.tests.*', 'com.oracle.graal.jtt.*']
         for p in mx.projects():
-            excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True)
-            excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True)
+            excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True).keys()
+            excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True).keys()
             
         includes = ['com.oracle.graal.*', 'com.oracle.max.*']
         agentOptions = {
@@ -732,7 +732,7 @@
 
     classes = []
     for p in mx.projects():
-        classes += _find_classes_with_annotations(p, None, annotations)
+        classes += _find_classes_with_annotations(p, None, annotations).keys()
 
         if len(pos) != 0:
             classes = [c for c in classes if containsAny(c, pos)]
@@ -1025,7 +1025,7 @@
     vm = _vm
     if len(args) is 0:
         args = ['all']
-        
+    
     vmArgs = [arg for arg in args if arg.startswith('-')]
 
     def benchmarks_in_group(group):
--- a/mx/projects	Thu Mar 28 17:11:06 2013 +0100
+++ b/mx/projects	Wed Apr 03 14:41:22 2013 +0200
@@ -23,7 +23,7 @@
 library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 
 distribution@GRAAL@path=graal.jar
-distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.sparc
+distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.sparc,com.oracle.graal.hotspot
 
 # graal.api.runtime
 project@com.oracle.graal.api.runtime@subDir=graal
@@ -98,7 +98,7 @@
 project@com.oracle.graal.hotspot@sourceDirs=src
 project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.printer
 project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier
+project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier, com.oracle.graal.service.processor
 project@com.oracle.graal.hotspot@javaCompliance=1.7
 
 # graal.hotspot.amd64
@@ -437,3 +437,5 @@
 project@com.oracle.truffle.sl.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.truffle.sl.test@javaCompliance=1.7
 
+
+
--- a/mxtool/mx.py	Thu Mar 28 17:11:06 2013 +0100
+++ b/mxtool/mx.py	Wed Apr 03 14:41:22 2013 +0200
@@ -311,10 +311,10 @@
     def find_classes_with_matching_source_line(self, pkgRoot, function, includeInnerClasses=False):
         """
         Scan the sources of this project for Java source files containing a line for which
-        'function' returns true. The fully qualified class name of each existing class
-        corresponding to a matched source file is returned in a list.
+        'function' returns true. A map from class name to source file path for each existing class
+        corresponding to a matched source file is returned.
         """
-        classes = []
+        result = dict()
         pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$")
         for srcDir in self.source_dirs():
             outputDir = self.output_dir()
@@ -322,7 +322,8 @@
                 for name in files:
                     if name.endswith('.java') and name != 'package-info.java':
                         matchFound = False
-                        with open(join(root, name)) as f:
+                        source = join(root, name)
+                        with open(source) as f:
                             pkg = None
                             for line in f:
                                 if line.startswith("package "):
@@ -342,10 +343,12 @@
                                 for e in os.listdir(pkgOutputDir):
                                     if includeInnerClasses:
                                         if e.endswith('.class') and (e.startswith(basename) or e.startswith(basename + '$')):
-                                            classes.append(pkg + '.' + e[:-len('.class')])
+                                            className = pkg + '.' + e[:-len('.class')]
+                                            result[className] = source 
                                     elif e == basename + '.class':
-                                        classes.append(pkg + '.' + basename)
-        return classes
+                                        className = pkg + '.' + basename
+                                        result[className] = source 
+        return result
     
     def _init_packages_and_imports(self):
         if not hasattr(self, '_defined_java_packages'):
@@ -1659,46 +1662,56 @@
             d = distribution(dname)
             fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path))
             services = tempfile.mkdtemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path))
-            zf = zipfile.ZipFile(tmp, 'w')
-            for p in sorted_deps(d.deps):
-                outputDir = p.output_dir()
-                for root, _, files in os.walk(outputDir):
-                    relpath = root[len(outputDir) + 1:]
-                    if relpath == join('META-INF', 'services'):
-                        for f in files:
-                            with open(join(services, f), 'a') as outfile:
-                                with open(join(root, f), 'r') as infile:
-                                    for line in infile:
-                                        outfile.write(line)
-                    else:
-                        for f in files:
-                            arcname = join(relpath, f).replace(os.sep, '/')
-                            zf.write(join(root, f), arcname)
-            for f in os.listdir(services):
-                arcname = join('META-INF', 'services', f).replace(os.sep, '/')
-                zf.write(join(services, f), arcname)
-            zf.close()
-            os.close(fd)
-            shutil.rmtree(services)
-            # Atomic on Unix
-            shutil.move(tmp, d.path)
-            #print time.time(), 'move:', tmp, '->', d.path
-            d.notify_updated()
+            try:
+                zf = zipfile.ZipFile(tmp, 'w')
+                for p in sorted_deps(d.deps):
+                    outputDir = p.output_dir()
+                    for root, _, files in os.walk(outputDir):
+                        relpath = root[len(outputDir) + 1:]
+                        if relpath == join('META-INF', 'services'):
+                            for f in files:
+                                with open(join(services, f), 'a') as outfile:
+                                    with open(join(root, f), 'r') as infile:
+                                        for line in infile:
+                                            outfile.write(line)
+                        else:
+                            for f in files:
+                                arcname = join(relpath, f).replace(os.sep, '/')
+                                zf.write(join(root, f), arcname)
+                for f in os.listdir(services):
+                    arcname = join('META-INF', 'services', f).replace(os.sep, '/')
+                    zf.write(join(services, f), arcname)
+                zf.close()
+                os.close(fd)
+                shutil.rmtree(services)
+                # Atomic on Unix
+                shutil.move(tmp, d.path)
+                #print time.time(), 'move:', tmp, '->', d.path
+                d.notify_updated()
+            finally:
+                if exists(tmp):
+                    os.remove(tmp)
+                if exists(services):
+                    shutil.rmtree(services)
 
         else:
             p = project(name)
             outputDir = p.output_dir()
             fd, tmp = tempfile.mkstemp(suffix='', prefix=p.name, dir=p.dir)
-            zf = zipfile.ZipFile(tmp, 'w')
-            for root, _, files in os.walk(outputDir):
-                for f in files:
-                    relpath = root[len(outputDir) + 1:]
-                    arcname = join(relpath, f).replace(os.sep, '/')
-                    zf.write(join(root, f), arcname)
-            zf.close()
-            os.close(fd)
-            # Atomic on Unix
-            shutil.move(tmp, join(p.dir, p.name + '.jar'))
+            try:
+                zf = zipfile.ZipFile(tmp, 'w')
+                for root, _, files in os.walk(outputDir):
+                    for f in files:
+                        relpath = root[len(outputDir) + 1:]
+                        arcname = join(relpath, f).replace(os.sep, '/')
+                        zf.write(join(root, f), arcname)
+                zf.close()
+                os.close(fd)
+                # Atomic on Unix
+                shutil.move(tmp, join(p.dir, p.name + '.jar'))
+            finally:
+                if exists(tmp):
+                    os.remove(tmp)
 
 def canonicalizeprojects(args):
     """process all project files to canonicalize the dependencies
--- a/src/cpu/x86/vm/templateInterpreter_x86.hpp	Thu Mar 28 17:11:06 2013 +0100
+++ b/src/cpu/x86/vm/templateInterpreter_x86.hpp	Wed Apr 03 14:41:22 2013 +0200
@@ -34,7 +34,7 @@
   // Run with +PrintInterpreter to get the VM to print out the size.
   // Max size with JVMTI
 #ifdef AMD64
-  const static int InterpreterCodeSize = 240 * 1024;
+  const static int InterpreterCodeSize = 224 * 1024;
 #else
   const static int InterpreterCodeSize = 168 * 1024;
 #endif // AMD64
--- a/src/share/vm/classfile/systemDictionary.hpp	Thu Mar 28 17:11:06 2013 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed Apr 03 14:41:22 2013 +0200
@@ -192,6 +192,7 @@
   do_klass(HotSpotResolvedJavaField_klass,        com_oracle_graal_hotspot_meta_HotSpotResolvedJavaField,       Opt) \
   do_klass(HotSpotResolvedJavaMethod_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod,      Opt) \
   do_klass(HotSpotResolvedObjectType_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,      Opt) \
+  do_klass(HotSpotMonitorValue_klass,             com_oracle_graal_hotspot_meta_HotSpotMonitorValue,            Opt) \
   do_klass(LocalImpl_klass,                       com_oracle_graal_hotspot_debug_LocalImpl,                     Opt) \
   /* graal.api.code */                                                                                               \
   do_klass(Assumptions_klass,                     com_oracle_graal_api_code_Assumptions,                        Opt) \
@@ -208,7 +209,6 @@
   do_klass(CompilationResult_Mark_klass,          com_oracle_graal_api_code_CompilationResult_Mark,             Opt) \
   do_klass(CompilationResult_Safepoint_klass,     com_oracle_graal_api_code_CompilationResult_Safepoint,        Opt) \
   do_klass(CompilationResult_Site_klass,          com_oracle_graal_api_code_CompilationResult_Site,             Opt) \
-  do_klass(code_MonitorValue_klass,               com_oracle_graal_api_code_MonitorValue,                       Opt) \
   do_klass(code_Register_klass,                   com_oracle_graal_api_code_Register,                           Opt) \
   do_klass(RegisterValue_klass,                   com_oracle_graal_api_code_RegisterValue,                      Opt) \
   do_klass(StackSlot_klass,                       com_oracle_graal_api_code_StackSlot,                          Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Thu Mar 28 17:11:06 2013 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Apr 03 14:41:22 2013 +0200
@@ -303,6 +303,7 @@
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaField,   "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField")        \
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod,  "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod")       \
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,  "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType")       \
+  template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue")             \
   template(com_oracle_graal_hotspot_debug_LocalImpl,                 "com/oracle/graal/hotspot/debug/LocalImpl")                      \
   AMD64_ONLY(template(com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime,"com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime"))\
   /* graal.api.meta */                                                                                                                \
@@ -329,7 +330,6 @@
   template(com_oracle_graal_api_code_BytecodeFrame,                  "com/oracle/graal/api/code/BytecodeFrame")                       \
   template(com_oracle_graal_api_code_BytecodePosition,               "com/oracle/graal/api/code/BytecodePosition")                    \
   template(com_oracle_graal_api_code_DebugInfo,                      "com/oracle/graal/api/code/DebugInfo")                           \
-  template(com_oracle_graal_api_code_MonitorValue,                   "com/oracle/graal/api/code/MonitorValue")                        \
   template(com_oracle_graal_api_code_Register,                       "com/oracle/graal/api/code/Register")                            \
   template(com_oracle_graal_api_code_RegisterValue,                  "com/oracle/graal/api/code/RegisterValue")                       \
   template(com_oracle_graal_api_code_StackSlot,                      "com/oracle/graal/api/code/StackSlot")                           \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Mar 28 17:11:06 2013 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Wed Apr 03 14:41:22 2013 +0200
@@ -263,19 +263,19 @@
 }
 
 static MonitorValue* get_monitor_value(oop value, int total_frame_size, GrowableArray<ScopeValue*>* objects, OopRecorder* oop_recorder) {
-  guarantee(value->is_a(code_MonitorValue::klass()), "Monitors must be of type MonitorValue");
+  guarantee(value->is_a(HotSpotMonitorValue::klass()), "Monitors must be of type MonitorValue");
 
   ScopeValue* second = NULL;
-  ScopeValue* owner_value = get_hotspot_value(code_MonitorValue::owner(value), total_frame_size, objects, second, oop_recorder);
+  ScopeValue* owner_value = get_hotspot_value(HotSpotMonitorValue::owner(value), total_frame_size, objects, second, oop_recorder);
   assert(second == NULL, "monitor cannot occupy two stack slots");
 
-  ScopeValue* lock_data_value = get_hotspot_value(code_MonitorValue::lockData(value), total_frame_size, objects, second, oop_recorder);
+  ScopeValue* lock_data_value = get_hotspot_value(HotSpotMonitorValue::slot(value), total_frame_size, objects, second, oop_recorder);
   assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots");
   assert(lock_data_value->is_location(), "invalid monitor location");
   Location lock_data_loc = ((LocationValue*)lock_data_value)->location();
 
   bool eliminated = false;
-  if (code_MonitorValue::eliminated(value)) {
+  if (HotSpotMonitorValue::eliminated(value)) {
     eliminated = true;
   }
 
--- a/src/share/vm/graal/graalJavaAccess.hpp	Thu Mar 28 17:11:06 2013 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Wed Apr 03 14:41:22 2013 +0200
@@ -197,10 +197,10 @@
     oop_field(VirtualObject, type, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                                             \
     oop_field(VirtualObject, values, "[Lcom/oracle/graal/api/meta/Value;")                                                                                     \
   end_class                                                                                                                                                    \
-  start_class(code_MonitorValue)                                                                                                                               \
-    oop_field(code_MonitorValue, owner, "Lcom/oracle/graal/api/meta/Value;")                                                                                   \
-    oop_field(code_MonitorValue, lockData, "Lcom/oracle/graal/api/meta/Value;")                                                                                \
-    boolean_field(code_MonitorValue, eliminated)                                                                                                               \
+  start_class(HotSpotMonitorValue)                                                                                                                               \
+    oop_field(HotSpotMonitorValue, owner, "Lcom/oracle/graal/api/meta/Value;")                                                                                   \
+    oop_field(HotSpotMonitorValue, slot, "Lcom/oracle/graal/api/code/StackSlot;")                                                                                \
+    boolean_field(HotSpotMonitorValue, eliminated)                                                                                                               \
   end_class                                                                                                                                                    \
   /* end*/