changeset 13570:d7af2296cebb

Merge with 4fc8c8bb4c32878cc04b064d2ac9ad1fce1a85e0
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Wed, 08 Jan 2014 15:49:18 -0800
parents 1894412de0ed (current diff) 4fc8c8bb4c32 (diff)
children 1335577dc50c 5335d65fec56
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java
diffstat 59 files changed, 626 insertions(+), 540 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Jan 08 15:49:18 2014 -0800
@@ -147,7 +147,6 @@
 
     @Override
     public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) {
-        assert (scale >= 1 && scale <= 8) || index.equals(Value.ILLEGAL) : "invalid scale";
         AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Wed Jan 08 15:49:18 2014 -0800
@@ -1839,7 +1839,7 @@
         /*
          * This is the point to enable debug logging for the whole register allocation.
          */
-        Indent indent = Debug.logAndIndent(false, "LinearScan allocate %s", gen.getGraph().method());
+        Indent indent = Debug.logAndIndent("LinearScan allocate %s", gen.getGraph().method());
 
         try (Scope s = Debug.scope("LifetimeAnalysis")) {
             numberInstructions();
@@ -1942,7 +1942,7 @@
 
     private void verifyRegisters() {
         // Enable this logging to get output for the verification process.
-        try (Indent indent = Debug.logAndIndent(false, "verifying register allocation")) {
+        try (Indent indent = Debug.logAndIndent("verifying register allocation")) {
             RegisterVerifier verifier = new RegisterVerifier(this);
             verifier.verify(blockAt(0));
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Wed Jan 08 15:49:18 2014 -0800
@@ -572,7 +572,7 @@
             // ignored safely
             if (Debug.isLogEnabled()) {
                 // Enable this logging to see all register states
-                try (Indent indent2 = Debug.logAndIndent(false, "state of registers:")) {
+                try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
                     for (Register register : availableRegs) {
                         int i = register.number;
                         Debug.log("reg %d: usePos: %d", register.number, usePos[i]);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Wed Jan 08 15:49:18 2014 -0800
@@ -169,7 +169,7 @@
      */
     public static Scope scope(String name, Object... context) {
         if (ENABLED) {
-            return DebugScope.getInstance().scope(name, false, null, context);
+            return DebugScope.getInstance().scope(name, null, context);
         } else {
             return null;
         }
@@ -198,7 +198,7 @@
     public static Scope sandbox(String name, DebugConfig config, Object... context) {
         if (ENABLED) {
             DebugConfig sandboxConfig = config == null ? silentConfig() : config;
-            return DebugScope.getInstance().scope(name, true, sandboxConfig, context);
+            return DebugScope.getInstance().scope(name, sandboxConfig, context);
         } else {
             return null;
         }
@@ -263,10 +263,6 @@
         }
 
         @Override
-        public void setEnabled(boolean enabled) {
-        }
-
-        @Override
         public Indent indent() {
             return this;
         }
@@ -304,22 +300,6 @@
     }
 
     /**
-     * Creates a new indentation level based on the last used Indent of the current DebugScope and
-     * turns on/off logging.
-     * 
-     * @param enabled If true, logging is enabled, otherwise disabled
-     * @return The new indentation level
-     */
-    public static Indent indent(boolean enabled) {
-        if (ENABLED) {
-            Indent logger = DebugScope.getInstance().pushIndentLogger();
-            logger.setEnabled(enabled);
-            return logger;
-        }
-        return noLoggerInstance;
-    }
-
-    /**
      * A convenience function which combines {@link #log} and {@link #indent()}.
      * 
      * @param msg The format string of the log message
@@ -336,28 +316,6 @@
         return noLoggerInstance;
     }
 
-    /**
-     * A convenience function which combines {@link #log} and {@link #indent(boolean)}.
-     * 
-     * @param enabled If true, logging is enabled, otherwise disabled
-     * @param msg The format string of the log message
-     * @param args The arguments referenced by the log message string
-     * @return The new indentation level
-     */
-    public static Indent logAndIndent(boolean enabled, String msg, Object... args) {
-        if (ENABLED) {
-            DebugScope scope = DebugScope.getInstance();
-            boolean saveLogEnabled = scope.isLogEnabled();
-            scope.setLogEnabled(enabled);
-            scope.log(msg, args);
-            scope.setLogEnabled(saveLogEnabled);
-            Indent indent = scope.pushIndentLogger();
-            indent.setEnabled(enabled);
-            return indent;
-        }
-        return noLoggerInstance;
-    }
-
     public static Iterable<Object> context() {
         if (ENABLED) {
             return DebugScope.getInstance().getCurrentContext();
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java	Wed Jan 08 15:49:18 2014 -0800
@@ -73,13 +73,6 @@
     void log(String msg, Object... args);
 
     /**
-     * Turns on/off logging for this indentation level.
-     * 
-     * @param enabled If true, logging is enabled, otherwise disabled
-     */
-    void setEnabled(boolean enabled);
-
-    /**
      * Creates a new indentation level (by adding some spaces).
      * 
      * @return The new indentation level
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Wed Jan 08 15:49:18 2014 -0800
@@ -35,13 +35,11 @@
         private static final String INDENTATION_INCREMENT = "  ";
 
         final String indent;
-        boolean enabled;
         final IndentImpl parentIndent;
 
-        IndentImpl(IndentImpl parentIndent, boolean enabled) {
+        IndentImpl(IndentImpl parentIndent) {
             this.parentIndent = parentIndent;
             this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT);
-            this.enabled = enabled;
         }
 
         private void printScopeName() {
@@ -56,7 +54,7 @@
 
         @Override
         public void log(String msg, Object... args) {
-            if (enabled) {
+            if (isLogEnabled()) {
                 printScopeName();
                 output.println(indent + String.format(msg, args));
                 lastUsedIndent = this;
@@ -64,13 +62,8 @@
         }
 
         @Override
-        public void setEnabled(boolean enabled) {
-            this.enabled = enabled;
-        }
-
-        @Override
         public Indent indent() {
-            lastUsedIndent = new IndentImpl(this, enabled);
+            lastUsedIndent = new IndentImpl(this);
             return lastUsedIndent;
         }
 
@@ -115,6 +108,7 @@
     private boolean meterEnabled;
     private boolean timeEnabled;
     private boolean dumpEnabled;
+    private boolean logEnabled;
 
     private PrintStream output;
 
@@ -141,10 +135,10 @@
         this.context = context;
         this.qualifiedName = qualifiedName;
         if (parent != null) {
-            lastUsedIndent = new IndentImpl(parent.lastUsedIndent, parent.isLogEnabled());
+            lastUsedIndent = new IndentImpl(parent.lastUsedIndent);
             logScopeName = !parent.qualifiedName.equals(qualifiedName);
         } else {
-            lastUsedIndent = new IndentImpl(null, false);
+            lastUsedIndent = new IndentImpl(null);
             logScopeName = true;
         }
 
@@ -169,7 +163,7 @@
 
     public void close() {
         instanceTL.set(parent);
-        setConfig(parentConfig);
+        configTL.set(parentConfig);
         lastClosedTL.set(this);
     }
 
@@ -178,11 +172,7 @@
     }
 
     public boolean isLogEnabled() {
-        return lastUsedIndent.enabled;
-    }
-
-    public void setLogEnabled(boolean enabled) {
-        lastUsedIndent.setEnabled(enabled);
+        return logEnabled;
     }
 
     public boolean isMeterEnabled() {
@@ -236,23 +226,21 @@
      * disjoint top level scope.
      * 
      * @param name the name of the new scope
-     * @param sandbox specifies if the scope is a child of the current scope or a top level scope
-     * @param sandboxConfig the configuration to use for a new top level scope (ignored if
-     *            {@code sandbox == false})
+     * @param sandboxConfig the configuration to use for a new top level scope, or null if the new
+     *            scope should be a child scope
      * @param context objects to be appended to the debug context
      * @return the new scope which will be exited when its {@link #close()} method is called
      */
     @SuppressWarnings("hiding")
-    public DebugScope scope(String name, boolean sandbox, DebugConfig sandboxConfig, Object... context) {
+    public DebugScope scope(String name, DebugConfig sandboxConfig, Object... context) {
         DebugScope newScope = null;
-        if (sandbox) {
+        if (sandboxConfig != null) {
             newScope = new DebugScope(name, name, this, true, context);
-            setConfig(sandboxConfig);
+            configTL.set(sandboxConfig);
         } else {
             newScope = this.createChild(name, context);
         }
         instanceTL.set(newScope);
-        newScope.setLogEnabled(this.isLogEnabled());
         newScope.updateFlags();
         return newScope;
     }
@@ -298,17 +286,15 @@
             meterEnabled = config.isMeterEnabled();
             timeEnabled = config.isTimeEnabled();
             dumpEnabled = config.isDumpEnabled();
+            logEnabled = config.isLogEnabled();
             output = config.output();
-            if (config.isLogEnabled()) {
-                setLogEnabled(true);
-            }
         }
     }
 
     private RuntimeException interceptException(final Throwable e) {
         final DebugConfig config = getConfig();
         if (config != null) {
-            try (DebugScope s = scope("InterceptException", false, null, e)) {
+            try (DebugScope s = scope("InterceptException", null, e)) {
                 return config.interceptException(e);
             } catch (Throwable t) {
                 return new RuntimeException("Exception while intercepting exception", t);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Wed Jan 08 15:49:18 2014 -0800
@@ -46,7 +46,7 @@
     }
 
     protected NodeList(T[] elements) {
-        if (elements == null) {
+        if (elements == null || elements.length == 0) {
             this.size = 0;
             this.nodes = EMPTY_NODE_ARRAY;
             this.initialSize = 0;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Wed Jan 08 15:49:18 2014 -0800
@@ -48,13 +48,13 @@
     }
 
     @Override
-    protected Value computeLockValue(FrameState state, int i) {
-        int lockDepth = i;
+    protected Value computeLockValue(FrameState state, int lockIndex) {
+        int lockDepth = lockIndex;
         if (state.outerFrameState() != null) {
             lockDepth += state.outerFrameState().nestedLockDepth();
         }
         StackSlot slot = lockStack.makeLockSlot(lockDepth);
-        ValueNode lock = state.lockAt(i);
+        ValueNode lock = state.lockAt(lockIndex);
         Value object = toValue(lock);
         boolean eliminated = lock instanceof VirtualObjectNode;
         return new HotSpotMonitorValue(object, slot, eliminated);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Jan 08 15:49:18 2014 -0800
@@ -310,67 +310,42 @@
                     FixedWithNextNode newObject;
                     if (virtual instanceof VirtualInstanceNode) {
                         newObject = graph.add(new NewInstanceNode(virtual.type(), true));
-                        graph.addBeforeFixed(commit, newObject);
-                        allocations[objIndex] = newObject;
-                        for (int i = 0; i < entryCount; i++) {
-                            ValueNode value = commit.getValues().get(valuePos);
-                            if (value instanceof VirtualObjectNode) {
-                                value = allocations[commit.getVirtualObjects().indexOf(value)];
-                            }
-                            if (value == null) {
-                                omittedValues.set(valuePos);
-                            } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                                // Constant.illegal is always the defaultForKind, so it is skipped
-                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                Kind accessKind;
-                                HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i);
-                                if (value.kind().getStackKind() != field.getKind().getStackKind()) {
-                                    assert value.kind() == Kind.Long || value.kind() == Kind.Double;
-                                    accessKind = value.kind();
-                                } else {
-                                    accessKind = field.getKind();
-                                }
-                                ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph);
-                                BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                                WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object);
-                                graph.addAfterFixed(newObject, graph.add(write));
-                            }
-                            valuePos++;
+                    } else {
+                        newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
+                    }
+                    graph.addBeforeFixed(commit, newObject);
+                    allocations[objIndex] = newObject;
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode value = commit.getValues().get(valuePos);
+                        if (value instanceof VirtualObjectNode) {
+                            value = allocations[commit.getVirtualObjects().indexOf(value)];
                         }
-                    } else {
-                        ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
-                        newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true));
-                        graph.addBeforeFixed(commit, newObject);
-                        allocations[objIndex] = newObject;
-                        for (int i = 0; i < entryCount; i++) {
-                            ValueNode value = commit.getValues().get(valuePos);
-                            if (value instanceof VirtualObjectNode) {
-                                value = allocations[commit.getVirtualObjects().indexOf(value)];
+                        if (value == null) {
+                            omittedValues.set(valuePos);
+                        } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                            // Constant.illegal is always the defaultForKind, so it is skipped
+                            Kind valueKind = value.kind();
+                            Kind entryKind = virtual.entryKind(i);
+
+                            // Truffle requires some leniency in terms of what can be put where:
+                            Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
+                            assert valueKind.getStackKind() == entryKind.getStackKind() ||
+                                            (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
+                            ConstantLocationNode location;
+                            BarrierType barrierType;
+                            if (virtual instanceof VirtualInstanceNode) {
+                                ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+                                location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
+                                barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+                            } else {
+                                location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
+                                barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
                             }
-                            if (value == null) {
-                                omittedValues.set(valuePos);
-                            } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                                // Constant.illegal is always the defaultForKind, so it is skipped
-                                Kind componentKind = element.getKind();
-                                Kind accessKind;
-                                Kind valueKind = value.kind();
-                                if (valueKind.getStackKind() != componentKind.getStackKind()) {
-                                    // Given how Truffle uses unsafe, it can happen that
-                                    // valueKind is Kind.Int
-                                    // assert valueKind == Kind.Long || valueKind == Kind.Double;
-                                    accessKind = valueKind;
-                                } else {
-                                    accessKind = componentKind;
-                                }
+                            WriteNode write = new WriteNode(newObject, value, location, barrierType, entryKind == Kind.Object);
+                            graph.addAfterFixed(newObject, graph.add(write));
+                        }
+                        valuePos++;
 
-                                int scale = getScalingFactor(componentKind);
-                                ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph);
-                                BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
-                                WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object);
-                                graph.addAfterFixed(newObject, graph.add(write));
-                            }
-                            valuePos++;
-                        }
                     }
                 }
                 valuePos = 0;
@@ -379,58 +354,28 @@
                     VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
                     int entryCount = virtual.entryCount();
                     ValueNode newObject = allocations[objIndex];
-                    if (virtual instanceof VirtualInstanceNode) {
-                        for (int i = 0; i < entryCount; i++) {
-                            if (omittedValues.get(valuePos)) {
-                                ValueNode value = commit.getValues().get(valuePos);
-                                assert value instanceof VirtualObjectNode;
-                                ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                                if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                    for (int i = 0; i < entryCount; i++) {
+                        if (omittedValues.get(valuePos)) {
+                            ValueNode value = commit.getValues().get(valuePos);
+                            assert value instanceof VirtualObjectNode;
+                            ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                            if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                                assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object;
+                                WriteNode write;
+                                if (virtual instanceof VirtualInstanceNode) {
                                     VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                    assert virtualInstance.field(i).getKind() == Kind.Object;
-                                    WriteNode write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true),
-                                                    BarrierType.IMPRECISE, true);
-                                    graph.addBeforeFixed(commit, graph.add(write));
+                                    write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), BarrierType.IMPRECISE, true);
+                                } else {
+                                    write = new WriteNode(newObject, allocValue, createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, true);
                                 }
+                                graph.addBeforeFixed(commit, graph.add(write));
                             }
-                            valuePos++;
                         }
-                    } else {
-                        ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
-                        for (int i = 0; i < entryCount; i++) {
-                            if (omittedValues.get(valuePos)) {
-                                ValueNode value = commit.getValues().get(valuePos);
-                                assert value instanceof VirtualObjectNode;
-                                ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                                if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                                    assert allocValue.kind() == Kind.Object;
-                                    WriteNode write = new WriteNode(newObject, allocValue, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE,
-                                                    true);
-                                    graph.addBeforeFixed(commit, graph.add(write));
-                                }
-                            }
-                            valuePos++;
-                        }
+                        valuePos++;
                     }
                 }
 
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
-                    allocations[objIndex] = anchor;
-                    graph.addBeforeFixed(commit, anchor);
-                }
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    for (int lockDepth : commit.getLocks().get(objIndex)) {
-                        MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
-                        graph.addBeforeFixed(commit, enter);
-                        enter.lower(tool);
-                    }
-                }
-                for (Node usage : commit.usages().snapshot()) {
-                    AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
-                    int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-                    graph.replaceFloating(addObject, allocations[index]);
-                }
+                finishAllocatedObjects(tool, commit, allocations);
                 graph.removeFixed(commit);
             }
         } else if (n instanceof OSRStartNode) {
@@ -529,6 +474,27 @@
         }
     }
 
+    protected static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
+        StructuredGraph graph = commit.graph();
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+            allocations[objIndex] = anchor;
+            graph.addBeforeFixed(commit, anchor);
+        }
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
+                graph.addBeforeFixed(commit, enter);
+                enter.lower(tool);
+            }
+        }
+        for (Node usage : commit.usages().snapshot()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+            graph.replaceFloating(addObject, allocations[index]);
+        }
+    }
+
     private static LocationNode createLocation(UnsafeAccessNode access) {
         ValueNode offset = access.offset();
         if (offset.isConstant()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Jan 08 15:49:18 2014 -0800
@@ -434,7 +434,7 @@
                 args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage());
             }
             args.add("object", monitorenterNode.object());
-            args.addConst("lockDepth", monitorenterNode.getLockDepth());
+            args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
             boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
             args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("stackPointerRegister", registers.getStackPointerRegister());
@@ -461,7 +461,7 @@
                 args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage());
             }
             args.add("object", monitorexitNode.object());
-            args.addConst("lockDepth", monitorexitNode.getLockDepth());
+            args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth());
             args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
 
             Map<Node, Node> nodes = template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
@@ -529,7 +529,7 @@
                         callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType));
                         invoke = graph.add(new InvokeNode(callTarget, 0));
                         List<ValueNode> stack = Collections.emptyList();
-                        FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false);
+                        FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], new MonitorIdNode[0], false, false);
                         invoke.setStateAfter(graph.add(stateAfter));
                         graph.addBeforeFixed(ret, invoke);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -25,6 +25,7 @@
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -138,7 +139,7 @@
                     newEntryState[i] = originalState.getEntry(i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
-                tool.createVirtualObject(newVirtual, newEntryState, null);
+                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList());
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
@@ -159,7 +160,7 @@
                     state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
                     tool.addNode(loads[i]);
                 }
-                tool.createVirtualObject(newVirtual, state, null);
+                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList());
                 tool.replaceWithVirtual(newVirtual);
             }
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Jan 08 15:49:18 2014 -0800
@@ -34,19 +34,22 @@
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 public class FrameStateBuilder {
 
     private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
 
     private final ResolvedJavaMethod method;
     private final StructuredGraph graph;
 
     private final ValueNode[] locals;
     private final ValueNode[] stack;
-    private ValueNode[] locks;
+    private ValueNode[] lockedObjects;
+    private MonitorIdNode[] monitorIds;
 
     private int stackSize;
 
@@ -62,7 +65,8 @@
         this.locals = new ValueNode[method.getMaxLocals()];
         // we always need at least one stack slot (for exceptions)
         this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())];
-        this.locks = EMPTY_ARRAY;
+        this.lockedObjects = EMPTY_ARRAY;
+        this.monitorIds = EMPTY_MONITOR_ARRAY;
 
         int javaIndex = 0;
         int index = 0;
@@ -100,12 +104,14 @@
         graph = other.graph;
         locals = other.locals.clone();
         stack = other.stack.clone();
-        locks = other.locks == EMPTY_ARRAY ? EMPTY_ARRAY : other.locks.clone();
+        lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone();
+        monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone();
         stackSize = other.stackSize;
         rethrowException = other.rethrowException;
 
         assert locals.length == method.getMaxLocals();
         assert stack.length == Math.max(1, method.getMaxStackSize());
+        assert lockedObjects.length == monitorIds.length;
     }
 
     @Override
@@ -120,8 +126,8 @@
             sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id));
         }
         sb.append("] locks: [");
-        for (int i = 0; i < locks.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locks[i] == null ? "_" : locks[i].toString(Verbosity.Id));
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
         }
         sb.append("]");
         if (rethrowException) {
@@ -132,7 +138,7 @@
     }
 
     public FrameState create(int bci) {
-        return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), locks, rethrowException, false));
+        return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false));
     }
 
     public FrameStateBuilder copy() {
@@ -141,6 +147,7 @@
 
     public boolean isCompatibleWith(FrameStateBuilder other) {
         assert method == other.method && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
 
         if (stackSize() != other.stackSize()) {
             return false;
@@ -152,11 +159,11 @@
                 return false;
             }
         }
-        if (locks.length != other.locks.length) {
+        if (lockedObjects.length != other.lockedObjects.length) {
             return false;
         }
-        for (int i = 0; i < locks.length; i++) {
-            if (GraphUtil.originalValue(locks[i]) != GraphUtil.originalValue(other.locks[i])) {
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
                 throw new BailoutException("unbalanced monitors");
             }
         }
@@ -172,8 +179,9 @@
         for (int i = 0; i < stackSize(); i++) {
             storeStack(i, merge(stackAt(i), other.stackAt(i), block));
         }
-        for (int i = 0; i < locks.length; i++) {
-            locks[i] = merge(locks[i], other.locks[i], block);
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
+            assert monitorIds[i] == other.monitorIds[i];
         }
     }
 
@@ -234,8 +242,8 @@
         for (int i = 0; i < stackSize(); i++) {
             storeStack(i, createLoopPhi(loopBegin, stackAt(i)));
         }
-        for (int i = 0; i < locks.length; i++) {
-            locks[i] = createLoopPhi(loopBegin, locks[i]);
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]);
         }
     }
 
@@ -254,11 +262,11 @@
                 storeStack(i, ProxyNode.forValue(value, loopExit, graph));
             }
         }
-        for (int i = 0; i < locks.length; i++) {
-            ValueNode value = locks[i];
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = ProxyNode.forValue(value, loopExit, graph);
+                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
             }
         }
     }
@@ -278,11 +286,11 @@
                 storeStack(i, ProxyNode.forValue(value, begin, graph));
             }
         }
-        for (int i = 0; i < locks.length; i++) {
-            ValueNode value = locks[i];
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = ProxyNode.forValue(value, begin, graph);
+                lockedObjects[i] = ProxyNode.forValue(value, begin, graph);
             }
         }
     }
@@ -373,10 +381,13 @@
      * 
      * @param object the object whose monitor will be locked.
      */
-    public void pushLock(ValueNode object) {
+    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
         assert object.isAlive() && object.kind() == Kind.Object : "unexpected value: " + object;
-        locks = Arrays.copyOf(locks, locks.length + 1);
-        locks[locks.length - 1] = object;
+        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
+        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
+        lockedObjects[lockedObjects.length - 1] = object;
+        monitorIds[monitorIds.length - 1] = monitorId;
+        assert lockedObjects.length == monitorIds.length;
     }
 
     /**
@@ -386,17 +397,23 @@
      */
     public ValueNode popLock() {
         try {
-            return locks[locks.length - 1];
+            return lockedObjects[lockedObjects.length - 1];
         } finally {
-            locks = locks.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(locks, locks.length - 1);
+            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
+            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
         }
     }
 
+    public MonitorIdNode peekMonitorId() {
+        return monitorIds[monitorIds.length - 1];
+    }
+
     /**
      * @return the current lock depth
      */
     public int lockDepth() {
-        return locks.length;
+        assert lockedObjects.length == monitorIds.length;
+        return lockedObjects.length;
     }
 
     /**
@@ -660,8 +677,9 @@
                 return true;
             }
         }
-        for (int i = 0; i < locks.length; i++) {
-            if (locks[i] == value) {
+        assert lockedObjects.length == monitorIds.length;
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (lockedObjects[i] == value || monitorIds[i] == value) {
                 return true;
             }
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 08 15:49:18 2014 -0800
@@ -217,7 +217,7 @@
             TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), "  "));
         }
 
-        Indent indent = Debug.logAndIndent(false, "build graph for %s", method);
+        Indent indent = Debug.logAndIndent("build graph for %s", method);
 
         // compute the block map, setup exception handlers and get the entrypoint(s)
         BciBlockMapping blockMap = createBlockMap();
@@ -1247,17 +1247,19 @@
     }
 
     private MonitorEnterNode genMonitorEnter(ValueNode x) {
-        MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, frameState.lockDepth()));
-        frameState.pushLock(x);
+        MonitorIdNode monitorId = currentGraph.add(new MonitorIdNode(frameState.lockDepth()));
+        MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId));
+        frameState.pushLock(x, monitorId);
         return monitorEnter;
     }
 
     private MonitorExitNode genMonitorExit(ValueNode x, ValueNode returnValue) {
+        MonitorIdNode monitorId = frameState.peekMonitorId();
         ValueNode lockedObject = frameState.popLock();
         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 = append(new MonitorExitNode(x, returnValue, frameState.lockDepth()));
+        MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, returnValue));
         return monitorExit;
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Jan 08 15:49:18 2014 -0800
@@ -31,6 +31,7 @@
 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.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 public abstract class LoopFragment {
@@ -198,11 +199,13 @@
                         markFloating(obj, nodes, notloopNodes);
                     }
                 }
+                if (n instanceof MonitorEnterNode) {
+                    markFloating(((MonitorEnterNode) n).getMonitorId(), nodes, notloopNodes);
+                }
                 for (Node usage : n.usages()) {
                     markFloating(usage, nodes, notloopNodes);
                 }
             }
-
         }
 
         return nodes;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Jan 08 15:49:18 2014 -0800
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -81,8 +82,13 @@
 
     @Input private FrameState outerFrameState;
 
+    /**
+     * Contains the locals, the expressions and the locked objects, in this order.
+     */
     @Input private final NodeInputList<ValueNode> values;
 
+    @Input private final NodeInputList<MonitorIdNode> monitorIds;
+
     @Input private final NodeInputList<EscapeObjectState> virtualObjectMappings;
 
     /**
@@ -93,16 +99,20 @@
     private final ResolvedJavaMethod method;
 
     /**
-     * Creates a {@code FrameState} for the given scope and maximum number of stack and local
-     * variables.
+     * Creates a {@code FrameState} with the given locals, stack expressions and locked monitors.
      * 
      * @param method the method for this frame state
      * @param bci the bytecode index of the frame state
-     * @param stackSize size of the stack
-     * @param rethrowException if true the VM should re-throw the exception on top of the stack when
-     *            deopt'ing using this framestate
+     * @param values the locals, stack expressions and locked objects, in this order
+     * @param localsSize the number of locals in the values list
+     * @param stackSize the number of stack expressions in the values list
+     * @param rethrowException if true, this FrameState will throw an exception (taken from the top
+     *            of the expression stack) during deoptimization
+     * @param duringCall true if this FrameState describes the state during a call
+     * @param monitorIds one MonitorIdNode for each locked object
+     * @param virtualObjectMappings a description of the current state for every virtual object
      */
-    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall,
+    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall, List<MonitorIdNode> monitorIds,
                     List<EscapeObjectState> virtualObjectMappings) {
         assert stackSize >= 0;
         this.method = method;
@@ -110,10 +120,12 @@
         this.localsSize = localsSize;
         this.stackSize = stackSize;
         this.values = new NodeInputList<>(this, values);
+        this.monitorIds = new NodeInputList<>(this, monitorIds);
         this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
         this.rethrowException = rethrowException;
         this.duringCall = duringCall;
         assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
+        assert values.size() - localsSize - stackSize == monitorIds.size();
     }
 
     /**
@@ -122,11 +134,12 @@
      * @param bci marker bci, needs to be < 0
      */
     public FrameState(int bci) {
-        this(null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<EscapeObjectState> emptyList());
+        this(null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<MonitorIdNode> emptyList(), Collections.<EscapeObjectState> emptyList());
+        assert bci == BEFORE_BCI || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == UNKNOWN_BCI || bci == INVALID_FRAMESTATE_BCI;
     }
 
-    public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, boolean rethrowException, boolean duringCall) {
-        this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Collections.<EscapeObjectState> emptyList());
+    public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, MonitorIdNode[] monitorIds, boolean rethrowException, boolean duringCall) {
+        this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Arrays.asList(monitorIds), Collections.<EscapeObjectState> emptyList());
     }
 
     private static List<ValueNode> createValues(ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks) {
@@ -198,7 +211,7 @@
      * Gets a copy of this frame state.
      */
     public FrameState duplicate(int newBci) {
-        FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -224,7 +237,7 @@
         for (EscapeObjectState state : virtualObjectMappings) {
             newVirtualMappings.add(state.duplicateWithVirtualState());
         }
-        FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, newVirtualMappings));
+        FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings));
         other.setOuterFrameState(newOuterFrameState);
         return other;
     }
@@ -248,7 +261,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -319,6 +332,14 @@
         return values.get(localsSize + stackSize + i);
     }
 
+    /**
+     * Get the MonitorIdNode that corresponds to the locked object at the specified index.
+     */
+    public MonitorIdNode monitorIdAt(int i) {
+        assert i >= 0 && i < locksSize();
+        return monitorIds.get(i);
+    }
+
     public NodeIterable<FrameState> innerFrameStates() {
         return usages().filter(FrameState.class);
     }
@@ -375,9 +396,10 @@
 
     @Override
     public boolean verify() {
+        assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
         for (ValueNode value : values) {
-            assert assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
-            assert assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value);
+            assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
+            assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value);
         }
         return super.verify();
     }
@@ -387,6 +409,9 @@
         for (ValueNode value : values.nonNull()) {
             closure.apply(this, value);
         }
+        for (MonitorIdNode monitorId : monitorIds) {
+            closure.apply(this, monitorId);
+        }
         for (EscapeObjectState state : virtualObjectMappings) {
             state.applyToNonVirtual(closure);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Jan 08 15:49:18 2014 -0800
@@ -200,7 +200,7 @@
     // Connect blocks (including loop backward edges), but ignoring dead code (blocks with id < 0).
     private void connectBlocks() {
         for (Block block : reversePostOrder) {
-            List<Block> predecessors = new ArrayList<>();
+            List<Block> predecessors = new ArrayList<>(4);
             for (Node predNode : block.getBeginNode().cfgPredecessors()) {
                 Block predBlock = nodeToBlock.get(predNode);
                 if (predBlock.id >= 0) {
@@ -217,7 +217,7 @@
             }
             block.predecessors = predecessors;
 
-            List<Block> successors = new ArrayList<>();
+            List<Block> successors = new ArrayList<>(4);
             for (Node suxNode : block.getEndNode().cfgSuccessors()) {
                 Block suxBlock = nodeToBlock.get(suxNode);
                 assert suxBlock.id >= 0;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -22,11 +22,14 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -79,7 +82,7 @@
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, null);
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList());
         tool.replaceWithVirtual(newVirtual);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java	Wed Jan 08 14:03:36 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.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/java/AccessMonitorNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -36,18 +36,24 @@
 public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint {
 
     @Input private ValueNode object;
+    @Input private MonitorIdNode monitorId;
 
     public ValueNode object() {
         return object;
     }
 
+    public MonitorIdNode getMonitorId() {
+        return monitorId;
+    }
+
     /**
      * Creates a new AccessMonitor instruction.
      * 
      * @param object the instruction producing the object
      */
-    public AccessMonitorNode(ValueNode object) {
+    public AccessMonitorNode(ValueNode object, MonitorIdNode monitorId) {
         super(StampFactory.forVoid());
         this.object = object;
+        this.monitorId = monitorId;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -30,18 +30,15 @@
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single, MonitorReference {
-
-    private int lockDepth;
+public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     /**
      * Creates a new MonitorEnterNode.
      * 
      * @param object the instruction producing the object
      */
-    public MonitorEnterNode(ValueNode object, int lockDepth) {
-        super(object);
-        this.lockDepth = lockDepth;
+    public MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) {
+        super(object, monitorId);
     }
 
     @Override
@@ -54,19 +51,11 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
-        this.lockDepth = lockDepth;
-    }
-
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
         if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
-            state.addLock(getLockDepth());
+            state.addLock(getMonitorId());
             tool.delete();
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -34,19 +34,16 @@
  * a synchronized method, then the return value of the method will be referenced, so that it will be
  * materialized before releasing the monitor.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference {
+public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single {
 
     @Input private ValueNode escapedReturnValue;
 
-    private int lockDepth;
-
     /**
      * Creates a new MonitorExitNode.
      */
-    public MonitorExitNode(ValueNode object, ValueNode escapedReturnValue, int lockDepth) {
-        super(object);
+    public MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) {
+        super(object, monitorId);
         this.escapedReturnValue = escapedReturnValue;
-        this.lockDepth = lockDepth;
     }
 
     public void setEscapedReturnValue(ValueNode x) {
@@ -73,22 +70,17 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
-        this.lockDepth = lockDepth;
-    }
-
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
         // the monitor exit for a synchronized method should never be virtualized
         assert stateAfter().bci != FrameState.AFTER_BCI || state == null;
         if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
-            int removedLock = state.removeLock();
-            assert removedLock == getLockDepth();
+            MonitorIdNode removedLock = state.removeLock();
+            if (removedLock != getMonitorId()) {
+                throw new GraalInternalError("mismatch at %s: %s vs. %s", this, removedLock, getMonitorId());
+            }
+            assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
             tool.delete();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * This node describes one locking scope; it ties the monitor enter, monitor exit and the frame
+ * states together. It is thus referenced from the {@link MonitorEnterNode}, from the
+ * {@link MonitorExitNode} and from the {@link FrameState}.
+ */
+public final class MonitorIdNode extends ValueNode implements IterableNodeType, LIRLowerable {
+
+    private int lockDepth;
+
+    public MonitorIdNode(int lockDepth) {
+        super(StampFactory.dependency());
+        this.lockDepth = lockDepth;
+    }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
+    public void generate(LIRGeneratorTool generator) {
+        // nothing to do
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -66,7 +68,7 @@
                     state[i] = defaultForKind;
                 }
                 VirtualObjectNode virtualObject = new VirtualArrayNode(elementType(), constantLength);
-                tool.createVirtualObject(virtualObject, state, null);
+                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
                 tool.replaceWithVirtual(virtualObject);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import java.lang.ref.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -74,7 +75,7 @@
             for (int i = 0; i < state.length; i++) {
                 state[i] = defaultFieldValue(fields[i]);
             }
-            tool.createVirtualObject(virtualObject, state, null);
+            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
             tool.replaceWithVirtual(virtualObject);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Jan 08 15:49:18 2014 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -45,9 +46,9 @@
 
         public abstract ValueNode getEntry(int index);
 
-        public abstract void addLock(int depth);
+        public abstract void addLock(MonitorIdNode monitorId);
 
-        public abstract int removeLock();
+        public abstract MonitorIdNode removeLock();
 
         public abstract ValueNode getMaterializedValue();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Jan 08 15:49:18 2014 -0800
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -66,7 +69,7 @@
      * @param entryState the initial state of the virtual object's fields.
      * @param locks the initial locking depths.
      */
-    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks);
+    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks);
 
     /**
      * Queries the current state of the given value: if it is virtualized (thread-local and the
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -36,7 +37,8 @@
 
     @Input private final NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
-    private List<int[]> locks = new ArrayList<>();
+    @Input private final NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
+    private ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
 
     public CommitAllocationNode() {
         super(StampFactory.forVoid());
@@ -50,13 +52,14 @@
         return values;
     }
 
-    public List<int[]> getLocks() {
-        return locks;
+    public List<MonitorIdNode> getLocks(int objIndex) {
+        return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1));
     }
 
     @Override
     public boolean verify() {
-        assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match " + virtualObjects + ", " + locks);
+        assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match " + virtualObjects + ", " + lockIndexes);
+        assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match " + lockIndexes + ", " + locks);
         int valueCount = 0;
         for (VirtualObjectNode virtual : virtualObjects) {
             valueCount += virtual.entryCount();
@@ -72,7 +75,12 @@
 
     @Override
     public void afterClone(Node other) {
-        locks = new ArrayList<>(((CommitAllocationNode) other).locks);
+        lockIndexes = new ArrayList<>(lockIndexes);
+    }
+
+    public void addLocks(List<MonitorIdNode> monitorIds) {
+        locks.addAll(monitorIds);
+        lockIndexes.add(locks.size());
     }
 
     @Override
@@ -81,7 +89,7 @@
         for (int i = 0; i < virtualObjects.size(); i++) {
             VirtualObjectNode virtualObject = virtualObjects.get(i);
             int entryCount = virtualObject.entryCount();
-            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), locks.get(i));
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i));
             pos += entryCount;
         }
         tool.delete();
@@ -100,8 +108,8 @@
                 s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id));
             }
             s.append("]");
-            if (locks.get(objIndex).length > 0) {
-                s.append(" locked(").append(Arrays.toString(locks.get(objIndex))).append(")");
+            if (!getLocks(objIndex).isEmpty()) {
+                s.append(" locked(").append(locks.get(objIndex)).append(")");
             }
             properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString());
         }
@@ -150,14 +158,17 @@
 
         if (usedCount < virtualObjects.size()) {
             List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
-            List<int[]> newLocks = new ArrayList<>(usedCount);
+            List<MonitorIdNode> newLocks = new ArrayList<>(usedCount);
+            ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1);
+            newLockIndexes.add(0);
             List<ValueNode> newValues = new ArrayList<>();
             int valuePos = 0;
             for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
                 VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
                 if (used[objIndex]) {
                     newVirtualObjects.add(virtualObject);
-                    newLocks.add(locks.get(objIndex));
+                    newLocks.addAll(getLocks(objIndex));
+                    newLockIndexes.add(newLocks.size());
                     newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
                 }
                 valuePos += virtualObject.entryCount();
@@ -168,6 +179,7 @@
             locks.addAll(newLocks);
             values.clear();
             values.addAll(newValues);
+            lockIndexes = newLockIndexes;
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/LockState.java	Wed Jan 08 15:49:18 2014 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * The class implements a simple linked list of MonitorIdNodes, which can be used to describe the
+ * current lock state of an object.
+ */
+public final class LockState {
+
+    public final MonitorIdNode monitorId;
+    public final LockState next;
+
+    public LockState(MonitorIdNode monitorId, LockState next) {
+        this.monitorId = monitorId;
+        this.next = next;
+    }
+
+    @Override
+    public String toString() {
+        return monitorId.getLockDepth() + (next == null ? "" : "," + next);
+    }
+
+    public static List<MonitorIdNode> asList(LockState state) {
+        if (state == null) {
+            return Collections.emptyList();
+        } else {
+            ArrayList<MonitorIdNode> result = new ArrayList<>();
+            LockState a = state;
+            do {
+                result.add(a.monitorId);
+                a = a.next;
+            } while (a != null);
+            return result;
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -141,7 +141,7 @@
     }
 
     @Override
-    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
         return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -41,9 +41,9 @@
     }
 
     @Override
-    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
         assert entries.length == 1;
-        assert locks.length == 0;
+        assert locks == null;
         return new BoxNode(entries[0], type(), boxingKind);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
         return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -88,7 +88,7 @@
      * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode}
      * , otherwise the node will just be added to the graph.
      */
-    public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks);
+    public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks);
 
     @Override
     public void generate(LIRGeneratorTool gen) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Jan 08 15:49:18 2014 -0800
@@ -1395,10 +1395,9 @@
         if (stateAfter != null) {
             FrameState outerFrameState = null;
             int callerLockDepth = stateAfter.nestedLockDepth();
-            for (Node inlinedNode : inlineGraph.getNodes()) {
-                Node node = duplicates.get(inlinedNode);
-                if (node instanceof FrameState) {
-                    FrameState frameState = (FrameState) node;
+            for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+                FrameState frameState = (FrameState) duplicates.get(original);
+                if (frameState != null) {
                     assert frameState.bci != FrameState.BEFORE_BCI : frameState;
                     if (frameState.bci == FrameState.AFTER_BCI) {
                         frameState.replaceAndDelete(stateAfter);
@@ -1421,8 +1420,10 @@
                         }
                     }
                 }
-                if (callerLockDepth != 0 && node instanceof MonitorReference) {
-                    MonitorReference monitor = (MonitorReference) node;
+            }
+            if (callerLockDepth != 0) {
+                for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
+                    MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
                     monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
                 }
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -102,7 +102,7 @@
         }
 
         @Override
-        public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+        public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
             if (allowMaterialization) {
                 return super.getMaterializedRepresentation(fixed, entries, locks);
             }
@@ -173,9 +173,9 @@
             tool.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
         }
 
-        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, null);
-        tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, null);
-        tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, null);
+        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList());
 
         assert frameFields.length == 6;
         ValueNode[] frameEntryState = new ValueNode[frameFields.length];
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jan 08 15:49:18 2014 -0800
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 
@@ -308,7 +309,7 @@
      * @param otherAllocations A list of allocations that need to be added before the rest (used for
      *            boxing allocations).
      */
-    public void addMaterializationBefore(final FixedNode position, final List<AllocatedObjectNode> objects, final List<int[]> locks, final List<ValueNode> values,
+    public void addMaterializationBefore(final FixedNode position, final List<AllocatedObjectNode> objects, final List<List<MonitorIdNode>> locks, final List<ValueNode> values,
                     final List<ValueNode> otherAllocations) {
         add(new Effect() {
 
@@ -341,7 +342,9 @@
                         obj.setCommit(commit);
                     }
                     commit.getValues().addAll(values);
-                    commit.getLocks().addAll(locks);
+                    for (List<MonitorIdNode> monitorIds : locks) {
+                        commit.addLocks(monitorIds);
+                    }
 
                     assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count();
                     List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Jan 08 15:49:18 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.nodes.*;
+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.*;
@@ -36,37 +37,6 @@
  */
 public class ObjectState extends Virtualizable.State {
 
-    private static final int[] EMPTY_INT_ARRAY = new int[0];
-
-    public static final class LockState {
-
-        public final int depth;
-        public final LockState next;
-
-        private LockState(int depth, LockState next) {
-            this.depth = depth;
-            this.next = next;
-        }
-
-        @Override
-        public String toString() {
-            return next == null ? String.valueOf(depth) : depth + "," + next;
-        }
-
-        public static boolean equals(LockState a, LockState b) {
-            if ((a == null) != (b == null)) {
-                return false;
-            }
-            if (a != null) {
-                if (a.depth != b.depth) {
-                    return false;
-                }
-                return equals(a.next, b.next);
-            }
-            return true;
-        }
-    }
-
     final VirtualObjectNode virtual;
 
     private EscapeState state;
@@ -74,17 +44,18 @@
     private ValueNode materializedValue;
     private LockState locks;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int[] locks) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks) {
+        this(virtual, entries, state, (LockState) null);
+        for (int i = locks.size() - 1; i >= 0; i--) {
+            this.locks = new LockState(locks.get(i), this.locks);
+        }
+    }
+
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks) {
         this.virtual = virtual;
         this.entries = entries;
         this.state = state;
-        if (locks == null) {
-            this.locks = null;
-        } else {
-            for (int i = locks.length - 1; i >= 0; i--) {
-                this.locks = new LockState(locks[i], this.locks);
-            }
-        }
+        this.locks = locks;
     }
 
     public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) {
@@ -156,37 +127,21 @@
     }
 
     @Override
-    public void addLock(int depth) {
-        locks = new LockState(depth, locks);
+    public void addLock(MonitorIdNode monitorId) {
+        locks = new LockState(monitorId, locks);
     }
 
     @Override
-    public int removeLock() {
+    public MonitorIdNode removeLock() {
         try {
-            return locks.depth;
+            return locks.monitorId;
         } finally {
             locks = locks.next;
         }
     }
 
-    public int[] getLocks() {
-        if (locks == null) {
-            return EMPTY_INT_ARRAY;
-        }
-        int cnt = 0;
-        LockState current = locks;
-        while (current != null) {
-            cnt++;
-            current = current.next;
-        }
-        int[] result = new int[cnt];
-        current = locks;
-        cnt = 0;
-        while (current != null) {
-            result[cnt++] = current.depth;
-            current = current.next;
-        }
-        return result;
+    public LockState getLocks() {
+        return locks;
     }
 
     public boolean hasLocks() {
@@ -194,7 +149,13 @@
     }
 
     public boolean locksEqual(ObjectState other) {
-        return LockState.equals(locks, other.locks);
+        LockState a = locks;
+        LockState b = other.locks;
+        while (a != null && b != null && a.monitorId == b.monitorId) {
+            a = a.next;
+            b = b.next;
+        }
+        return a == null && b == null;
     }
 
     @Override
@@ -220,7 +181,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + Arrays.hashCode(entries);
-        result = prime * result + (locks != null ? locks.depth : 0);
+        result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0);
         result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
         result = prime * result + ((state == null) ? 0 : state.hashCode());
         result = prime * result + ((virtual == null) ? 0 : virtual.hashCode());
@@ -239,7 +200,7 @@
         if (!Arrays.equals(entries, other.entries)) {
             return false;
         }
-        if (!LockState.equals(locks, other.locks)) {
+        if (!locksEqual(other)) {
             return false;
         }
         if (materializedValue == null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Jan 08 15:49:18 2014 -0800
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -68,15 +69,15 @@
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
         List<AllocatedObjectNode> objects = new ArrayList<>(2);
         List<ValueNode> values = new ArrayList<>(8);
-        List<int[]> locks = new ArrayList<>(2);
+        List<List<MonitorIdNode>> locks = new ArrayList<>(2);
         List<ValueNode> otherAllocations = new ArrayList<>(2);
         materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
 
         materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations);
     }
 
-    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<int[]> locks, List<ValueNode> values, List<ValueNode> otherAllocations,
-                    EscapeState state) {
+    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values,
+                    List<ValueNode> otherAllocations, EscapeState state) {
         ObjectState obj = getObjectState(virtual);
 
         ValueNode[] entries = obj.getEntries();
@@ -84,7 +85,7 @@
         obj.escape(representation, state);
         if (representation instanceof AllocatedObjectNode) {
             objects.add((AllocatedObjectNode) representation);
-            locks.add(obj.getLocks());
+            locks.add(LockState.asList(obj.getLocks()));
             int pos = values.size();
             while (values.size() < pos + entries.length) {
                 values.add(null);
@@ -104,7 +105,7 @@
         } else {
             VirtualUtil.trace("materialized %s as %s", virtual, representation);
             otherAllocations.add(representation);
-            assert obj.getLocks().length == 0;
+            assert obj.getLocks() == null;
         }
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Jan 08 15:49:18 2014 -0800
@@ -24,11 +24,14 @@
 
 import static com.oracle.graal.phases.GraalOptions.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.spi.*;
@@ -150,7 +153,7 @@
     }
 
     @Override
-    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) {
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks) {
         VirtualUtil.trace("{{%s}} ", current);
         if (!virtualObject.isAlive()) {
             effects.addFloatingNode(virtualObject, "newVirtualObject");
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -79,7 +79,7 @@
         this.name = name;
         this.isSplatted = isSplatted;
 
-        dispatchHead = adoptChild(adoptChild(new DispatchHeadNode(context, section, name, isSplatted)));
+        dispatchHead = adoptChild(new DispatchHeadNode(context, section, name, isSplatted));
     }
 
     @Override
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -13,6 +13,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.control.*;
 
@@ -28,7 +29,11 @@
 
     @Override
     public Object execute(VirtualFrame frame) {
-        throw new BreakException(child.execute(frame));
+        if (child instanceof NilNode) {
+            throw BreakException.NIL;
+        } else {
+            throw new BreakException(child.execute(frame));
+        }
     }
 
 }
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -13,19 +13,27 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.control.*;
 
 @NodeInfo(shortName = "next")
 public class NextNode extends RubyNode {
 
-    public NextNode(RubyContext context, SourceSection sourceSection) {
+    @Child private RubyNode child;
+
+    public NextNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
         super(context, sourceSection);
+
+        this.child = adoptChild(child);
     }
 
     @Override
     public Object execute(VirtualFrame frame) {
-        throw new NextException();
+        if (child instanceof NilNode) {
+            throw NextException.NIL;
+        } else {
+            throw new NextException(child.execute(frame));
+        }
     }
-
 }
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java	Wed Jan 08 15:49:18 2014 -0800
@@ -16,6 +16,7 @@
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
@@ -457,6 +458,10 @@
     @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
     public abstract static class EachNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public EachNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -466,12 +471,21 @@
         }
 
         @Specialization
-        public NilPlaceholder each(VirtualFrame frame, RubyArray array, RubyProc block) {
-            for (int n = 0; n < array.size(); n++) {
-                try {
-                    yield(frame, block, array.get(n));
-                } catch (BreakException e) {
-                    break;
+        public Object each(VirtualFrame frame, RubyArray array, RubyProc block) {
+            outer: for (int n = 0; n < array.size(); n++) {
+                while (true) {
+                    try {
+                        yield(frame, block, array.get(n));
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
                 }
             }
 
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java	Wed Jan 08 15:49:18 2014 -0800
@@ -14,7 +14,9 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
 import com.oracle.truffle.ruby.runtime.core.array.*;
 
@@ -602,6 +604,10 @@
     @CoreMethod(names = "times", needsBlock = true, maxArgs = 0)
     public abstract static class TimesNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public TimesNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -611,9 +617,22 @@
         }
 
         @Specialization
-        public BigInteger times(VirtualFrame frame, BigInteger n, RubyProc block) {
-            for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
-                yield(frame, block, i);
+        public Object times(VirtualFrame frame, BigInteger n, RubyProc block) {
+            outer: for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
+                while (true) {
+                    try {
+                        yield(frame, block, i);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return n;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java	Wed Jan 08 15:49:18 2014 -0800
@@ -14,7 +14,9 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
 import com.oracle.truffle.ruby.runtime.core.array.*;
 
@@ -755,6 +757,10 @@
     @CoreMethod(names = "times", needsBlock = true, maxArgs = 0)
     public abstract static class TimesNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public TimesNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -764,9 +770,22 @@
         }
 
         @Specialization
-        public int times(VirtualFrame frame, int n, RubyProc block) {
-            for (int i = 0; i < n; i++) {
-                yield(frame, block, i);
+        public Object times(VirtualFrame frame, int n, RubyProc block) {
+            outer: for (int i = 0; i < n; i++) {
+                while (true) {
+                    try {
+                        yield(frame, block, i);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return n;
@@ -831,6 +850,10 @@
     @CoreMethod(names = "upto", needsBlock = true, minArgs = 1, maxArgs = 1)
     public abstract static class UpToNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public UpToNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -840,9 +863,22 @@
         }
 
         @Specialization
-        public NilPlaceholder upto(VirtualFrame frame, int from, int to, RubyProc block) {
-            for (int i = from; i <= to; i++) {
-                yield(frame, block, i);
+        public Object upto(VirtualFrame frame, int from, int to, RubyProc block) {
+            outer: for (int i = from; i <= to; i++) {
+                while (true) {
+                    try {
+                        yield(frame, block, i);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return NilPlaceholder.INSTANCE;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java	Wed Jan 08 15:49:18 2014 -0800
@@ -44,7 +44,10 @@
                     hash.put(keyValue.get(0), keyValue.get(1));
                 }
             } else {
-                assert args.length % 2 == 0;
+                if (args.length % 2 != 0) {
+                    // TODO(CS): figure out what error to throw here
+                    throw new UnsupportedOperationException();
+                }
 
                 for (int n = 0; n < args.length; n += 2) {
                     hash.put(args[n], args[n + 1]);
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java	Wed Jan 08 15:49:18 2014 -0800
@@ -12,8 +12,10 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.nodes.call.*;
 import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
 import com.oracle.truffle.ruby.runtime.core.array.*;
 import com.oracle.truffle.ruby.runtime.core.range.*;
@@ -50,6 +52,10 @@
     @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
     public abstract static class EachNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public EachNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -59,9 +65,22 @@
         }
 
         @Specialization
-        public FixnumRange each(VirtualFrame frame, FixnumRange range, RubyProc block) {
-            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) {
-                yield(frame, block, n);
+        public Object each(VirtualFrame frame, FixnumRange range, RubyProc block) {
+            outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) {
+                while (true) {
+                    try {
+                        yield(frame, block, n);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return range;
@@ -182,6 +201,10 @@
     @CoreMethod(names = "step", needsBlock = true, minArgs = 1, maxArgs = 1)
     public abstract static class StepNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public StepNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -191,9 +214,22 @@
         }
 
         @Specialization
-        public FixnumRange step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) {
-            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) {
-                yield(frame, block, n);
+        public Object step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) {
+            outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) {
+                while (true) {
+                    try {
+                        yield(frame, block, n);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return range;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java	Wed Jan 08 15:49:18 2014 -0800
@@ -304,13 +304,13 @@
     }
 
     @CoreMethod(names = "inspect", maxArgs = 0)
-    public abstract static class InpsectNode extends CoreMethodNode {
+    public abstract static class InspectNode extends CoreMethodNode {
 
-        public InpsectNode(RubyContext context, SourceSection sourceSection) {
+        public InspectNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
 
-        public InpsectNode(InpsectNode prev) {
+        public InspectNode(InspectNode prev) {
             super(prev);
         }
 
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java	Wed Jan 08 15:49:18 2014 -0800
@@ -36,8 +36,7 @@
             return body.execute(frame);
         } catch (NextException e) {
             nextProfile.enter();
-            return NilPlaceholder.INSTANCE;
+            return e.getResult();
         }
     }
-
 }
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Wed Jan 08 15:49:18 2014 -0800
@@ -1513,7 +1513,17 @@
 
     @Override
     public Object visitNextNode(org.jrubyparser.ast.NextNode node) {
-        return new NextNode(context, translate(node.getPosition()));
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode resultNode;
+
+        if (node.getValueNode() == null) {
+            resultNode = new NilNode(context, sourceSection);
+        } else {
+            resultNode = (RubyNode) node.getValueNode().accept(this);
+        }
+
+        return new NextNode(context, sourceSection, resultNode);
     }
 
     @Override
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java	Wed Jan 08 15:49:18 2014 -0800
@@ -17,6 +17,8 @@
  */
 public final class BreakException extends ControlFlowException {
 
+    public static final BreakException NIL = new BreakException(NilPlaceholder.INSTANCE);
+
     private final Object result;
 
     public BreakException(Object result) {
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java	Wed Jan 08 14:03:36 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java	Wed Jan 08 15:49:18 2014 -0800
@@ -10,12 +10,27 @@
 package com.oracle.truffle.ruby.runtime.control;
 
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
 
 /**
  * Controls moving to the next iteration in a control structure or method.
  */
 public final class NextException extends ControlFlowException {
 
+    public static final NextException NIL = new NextException(NilPlaceholder.INSTANCE);
+
+    private final Object result;
+
+    public NextException(Object result) {
+        assert RubyContext.shouldObjectBeVisible(result);
+
+        this.result = result;
+    }
+
+    public Object getResult() {
+        return result;
+    }
+
     private static final long serialVersionUID = -302759969186731457L;
 
 }
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Wed Jan 08 15:49:18 2014 -0800
@@ -1601,7 +1601,7 @@
   }
 #endif // TIERED
   __ set((intptr_t)os::get_polling_page(), L0);
-  __ relocate(poll_return_Relocation::spec(poll_Relocation::absolute));
+  __ relocate(relocInfo::poll_return_type);
   __ ld_ptr(L0, 0, G0);
   __ ret();
   __ delayed()->restore();
@@ -1610,10 +1610,9 @@
 
 int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
   __ set((intptr_t)os::get_polling_page(), tmp->as_register());
+  __ relocate(relocInfo::poll_type);
   if (info != NULL) {
     add_debug_info_for_branch(info);
-  } else {
-    __ relocate(poll_Relocation::spec(poll_Relocation::absolute));
   }
 
   int offset = __ offset();
--- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp	Wed Jan 08 15:49:18 2014 -0800
@@ -188,13 +188,13 @@
       fatal("unimplemented");
     }
     case MARK_POLL_FAR:
-      _instructions->relocate(pc, poll_Relocation::spec(poll_Relocation::absolute));
+      _instructions->relocate(pc, relocInfo::poll_type);
       break;
     case MARK_POLL_RETURN_NEAR: {
       fatal("unimplemented");
     }
     case MARK_POLL_RETURN_FAR:
-      _instructions->relocate(pc, poll_return_Relocation::spec(poll_Relocation::absolute));
+      _instructions->relocate(pc, relocInfo::poll_return_type);
       break;
     default:
       fatal("invalid mark value");
--- a/src/cpu/x86/vm/assembler_x86.cpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/cpu/x86/vm/assembler_x86.cpp	Wed Jan 08 15:49:18 2014 -0800
@@ -81,10 +81,8 @@
     _rspec = runtime_call_Relocation::spec();
     break;
   case relocInfo::poll_type:
-    _rspec = poll_Relocation::spec(Assembler::is_polling_page_far() ? poll_Relocation::absolute : poll_Relocation::pc_relative);
-    break;
   case relocInfo::poll_return_type:
-    _rspec = poll_return_Relocation::spec(Assembler::is_polling_page_far() ? poll_Relocation::absolute : poll_Relocation::pc_relative);
+    _rspec = Relocation::spec_simple(rtype);
     break;
   case relocInfo::none:
     break;
--- a/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Wed Jan 08 15:49:18 2014 -0800
@@ -243,19 +243,24 @@
   switch (mark) {
     case MARK_POLL_NEAR: {
       relocate_poll_near(pc);
-      _instructions->relocate(pc, poll_Relocation::spec(poll_Relocation::pc_relative));
+      _instructions->relocate(pc, relocInfo::poll_type, Assembler::disp32_operand);
       break;
     }
     case MARK_POLL_FAR:
-      _instructions->relocate(pc, poll_Relocation::spec(poll_Relocation::absolute));
+      // This is a load from a register so there is no relocatable operand.
+      // We just have to ensure that the format is not disp32_operand
+      // so that poll_Relocation::fix_relocation_after_move does the right
+      // thing (i.e. ignores this relocation record)
+      _instructions->relocate(pc, relocInfo::poll_type, Assembler::imm_operand);
       break;
     case MARK_POLL_RETURN_NEAR: {
       relocate_poll_near(pc);
-      _instructions->relocate(pc, poll_return_Relocation::spec(poll_Relocation::pc_relative));
+      _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::disp32_operand);
       break;
     }
     case MARK_POLL_RETURN_FAR:
-      _instructions->relocate(pc, poll_return_Relocation::spec(poll_Relocation::absolute));
+      // see comment above for MARK_POLL_FAR
+      _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand);
       break;
     default:
       fatal("invalid mark value");
--- a/src/cpu/x86/vm/relocInfo_x86.cpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/cpu/x86/vm/relocInfo_x86.cpp	Wed Jan 08 15:49:18 2014 -0800
@@ -179,17 +179,14 @@
 
 void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
 #ifdef _LP64
-  if (_form == pc_relative) {
-    typedef Assembler::WhichOperand WhichOperand;
-    WhichOperand which = (WhichOperand) format();
-    // This format is imm but it is really disp32
-    which = Assembler::disp32_operand;
+  typedef Assembler::WhichOperand WhichOperand;
+  WhichOperand which = (WhichOperand) format();
+  if (which == Assembler::disp32_operand) {
     address orig_addr = old_addr_for(addr(), src, dest);
     NativeInstruction* oni = nativeInstruction_at(orig_addr);
     int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which);
     // This poll_addr is incorrect by the size of the instruction it is irrelevant
     intptr_t poll_addr = (intptr_t)oni + *orig_disp;
-
     NativeInstruction* ni = nativeInstruction_at(addr());
     intptr_t new_disp = poll_addr - (intptr_t) ni;
 
--- a/src/share/vm/c1/c1_LIRAssembler.cpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/share/vm/c1/c1_LIRAssembler.cpp	Wed Jan 08 15:49:18 2014 -0800
@@ -334,7 +334,6 @@
 
 
 void LIR_Assembler::add_debug_info_for_branch(CodeEmitInfo* info) {
-  _masm->code_section()->relocate(pc(), relocInfo::poll_type);
   int pc_offset = code_offset();
   flush_debug_info(pc_offset);
   info->record_debug_info(compilation()->debug_info_recorder(), pc_offset);
--- a/src/share/vm/code/relocInfo.cpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/share/vm/code/relocInfo.cpp	Wed Jan 08 15:49:18 2014 -0800
@@ -679,16 +679,6 @@
   _target  = address_from_scaled_offset(offset, base);
 }
 
-void poll_Relocation::pack_data_to(CodeSection* dest) {
-  short* p = (short*) dest->locs_end();
-  p = pack_1_int_to(p, _form);
-  dest->set_locs_end((relocInfo*) p);
-}
-
-void poll_Relocation::unpack_data() {
-  _form = (poll_Relocation::pollingForm) unpack_1_int();
-}
-
 //// miscellaneous methods
 oop* oop_Relocation::oop_addr() {
   int n = _oop_index;
@@ -985,22 +975,6 @@
       tty->print(" | [static_call=" INTPTR_FORMAT "]", r->static_call());
       break;
     }
-  case relocInfo::poll_type:
-  case relocInfo::poll_return_type:
-    {
-      poll_Relocation* r = (poll_Relocation*) reloc();
-      const char *formName = "unknown";
-      switch (r->form()) {
-        case poll_Relocation::pc_relative:
-          formName = "pc_relative";
-          break;
-        case poll_Relocation::absolute:
-          formName = "absolute";
-          break;
-      }
-      tty->print(" | [form=%d(%s)]", r->form(), formName);
-      break;
-    }
   }
   tty->cr();
 }
--- a/src/share/vm/code/relocInfo.hpp	Wed Jan 08 14:03:36 2014 -0800
+++ b/src/share/vm/code/relocInfo.hpp	Wed Jan 08 15:49:18 2014 -0800
@@ -213,8 +213,7 @@
 // relocInfo::poll_[return_]type -- a safepoint poll
 //   Value:  none
 //   Instruction types: memory load or test
-//   Data:  []       the associated set-oops are adjacent to the call
-//          [n]      n is a poll_Relocation::pollingForm value
+//   Data:  none
 //
 // For example:
 //
@@ -1277,53 +1276,15 @@
   section_word_Relocation() { }
 };
 
+
 class poll_Relocation : public Relocation {
- public:
-  enum pollingForm {
-    pc_relative,
-    absolute
-  };
+  bool          is_data()                      { return true; }
   relocInfo::relocType type() { return relocInfo::poll_type; }
-  bool          is_data()                      { return true; }
   void     fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest);
- private:
-  pollingForm     _form;
- public:
-
-  static RelocationHolder spec(poll_Relocation::pollingForm form) {
-    RelocationHolder rh = newHolder();
-    new(rh) poll_Relocation(form);
-    return rh;
-  }
-
-  poll_Relocation(poll_Relocation::pollingForm form) {
-    _form = form;
-  }
-  poll_Relocation::pollingForm form() { return _form; }
-
-  void pack_data_to(CodeSection* dest);
-  void unpack_data();
-
- protected:
-  friend class RelocIterator;
-  poll_Relocation() { }
 };
 
 class poll_return_Relocation : public poll_Relocation {
- public:
   relocInfo::relocType type() { return relocInfo::poll_return_type; }
-
-  static RelocationHolder spec(poll_Relocation::pollingForm distance) {
-    RelocationHolder rh = newHolder();
-    new(rh) poll_return_Relocation(distance);
-    return rh;
-  }
-
-  poll_return_Relocation(poll_Relocation::pollingForm distance) : poll_Relocation(distance) { }
-
- private:
-  friend class RelocIterator;
-  poll_return_Relocation() { }
 };
 
 // We know all the xxx_Relocation classes, so now we can define these: